Commit c5edc9ae authored by Gonzalo Fabian Cameto Hernandez's avatar Gonzalo Fabian Cameto Hernandez
Browse files

Seguridad en servicios

parent 0664a5e3
//export const SERVER = 'https://matefun.mybluemix.net';
//export const GHCI_URL = 'wss://matefun.mybluemix.net/endpoint';
//export const SERVER = 'http://localhost:9080';
//export const GHCI_URL = 'ws://localhost:9080/endpoint';
export const SERVER = 'http://localhost:9090';
export const GHCI_URL = 'ws://localhost:9090/endpoint';
//Configuracion dinamica pensando en servidor con ip dinamica
export const SERVER = window.location.protocol + '//' + window.location.host;//'http://localhost:9090';
export const GHCI_URL = window.location.protocol == 'http:'? 'ws://'+window.location.host+'/endpoint': 'wss://'+window.location.host+'/endpoint';
//export const SERVER = window.location.protocol + '//' + window.location.host;//'http://localhost:9090';
//export const GHCI_URL = window.location.protocol == 'http:'? 'ws://'+window.location.host+'/endpoint': 'wss://'+window.location.host+'/endpoint';
......@@ -15,12 +15,8 @@ export class AuthenticationService {
let options = new RequestOptions({ headers: headers });
return this.http.post(SERVER+'/servicios/login', JSON.stringify({ "cedula": cedula, "password": password }),options)
.map((response: Response) => {
// login successful if there's a jwt token in the response
let user = response.json();
// if (user && user.token) {
// store user details and jwt token in local storage to keep user logged in between page refreshes
sessionStorage.setItem('currentUser', JSON.stringify(user));
// }
sessionStorage.setItem('currentUser', JSON.stringify(user));
});
}
......
import { Injectable,ViewChild,ElementRef } from '@angular/core';
import { Router } from '@angular/router';
import { Observable, Subject } from 'rxjs/Rx';
import { WebsocketService } from './websocket.service';
import { AuthenticationService } from './authentication.service';
import { GHCI_URL } from '../config';
declare var $:any;
declare var that :any ;
const regex = /^color (errores|input|output|logs) (\d)$/g;
......@@ -32,7 +34,7 @@ export class GHCIService {
consoleBuffer = [];
constructor(private authService:AuthenticationService){
constructor(private authService:AuthenticationService,private router: Router){
console.log("contructor ghci");
this.conectarWS(GHCI_URL, authService.getUser().cedula, authService.getToken());
setInterval( this.checkConnection.bind(this), 5000);
......@@ -84,9 +86,13 @@ export class GHCIService {
this.connection.onopen = function(){
console.log('Conexión con web socket exitosa');
}
this.connection.onclose = function(){
console.log('Conexión con web socket cerrada');
}
this.connection.onclose = function(reason){
//Codigo que indica la falta de permisos (sesion expirada por ejemplo)
if(reason.code == 1008){
this.router.navigate(['/login']);
}
console.log('Conexión con web socket cerrada',reason);
}.bind(this)
this.connection.onmessage = this.onMessage.bind(this);
}
}
......
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Http, Response, Headers, RequestOptions, URLSearchParams } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { Archivo, Evaluacion } from '../objects/archivo';
......@@ -18,7 +19,7 @@ export class HaskellService {
* @param {Http} http - The injected Http.
* @constructor
*/
constructor(private http: Http, private authService: AuthenticationService) {}
constructor(private http: Http, private router: Router, private authService: AuthenticationService) {}
getArchivos(cedula:string): Observable<Archivo[]> {
let headers = new Headers({ 'Content-Type': 'application/json', 'Authorization':'Bearer '+this.authService.getToken() });
......@@ -109,6 +110,9 @@ export class HaskellService {
* Handle HTTP error
*/
private handleError (error: any) {
if(error.status == 401){
this.router.navigate(['/login']);
}
// In a real world app, we might use a remote logging infrastructure
// We'd also dig deeper into the error to get a better message
let errMsg = (error.message) ? error.message :
......
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Http, Headers, Response, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { Usuario, Configuracion } from '../objects/usuario';
import { AuthenticationService } from './authentication.service';
import 'rxjs/add/operator/map'
import 'rxjs/add/operator/catch'
......@@ -10,10 +12,10 @@ import { SERVER } from '../config';
@Injectable()
export class UsuarioService {
constructor(private http: Http) {}
constructor(private http: Http, private router: Router, private authService: AuthenticationService) {}
actualizarConfiguracion(cedula: string, config: Configuracion) {
let headers = new Headers({ 'Content-Type': 'application/json' });
let headers = new Headers({ 'Content-Type': 'application/json', 'Authorization':'Bearer '+this.authService.getToken() });
let options = new RequestOptions({ headers: headers });
return this.http.put(SERVER + '/servicios/usuario/' + cedula + "/configuracion", config, options)
.map(this.extractData)
......@@ -26,6 +28,9 @@ export class UsuarioService {
}
private handleError(error: any) {
if(error.status == 401){
this.router.navigate(['/login']);
}
let errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
console.error(errMsg); // log to console instead
......
......@@ -24,6 +24,8 @@ import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.json.JsonValue;
import javax.servlet.ServletContext;
import javax.websocket.CloseReason;
import javax.websocket.CloseReason.CloseCodes;
import javax.websocket.Session;
import edu.proygrado.dto.ArchivoDTO;
......@@ -41,6 +43,9 @@ public class CommandsBean {
@Inject
UsuarioEJB usuarioEJB;
@Inject
LoginEJB loginEJB;
@Inject
private ServletContext context;
......@@ -80,16 +85,24 @@ public class CommandsBean {
restartProcess(this.cedula, token, session);
System.err.println("Se reinicia el proceso.");
}
if(!loginEJB.validarSesion(token)){
session.close(new CloseReason(CloseCodes.VIOLATED_POLICY,"Sin permisos"));
System.out.print("Web socket finalizado");
return;
}
if (comandoJson.containsKey("ping")) {
// System.out.println(comandoJson.getString("ping"));
} else if (comandoJson.containsKey("comando")) {
loginEJB.extendSession(token);
String comando = comandoJson.getString("comando");
this.p_stdin.write(comando);
this.p_stdin.newLine();
this.p_stdin.flush();
} else if (comandoJson.containsKey("load")) {
loginEJB.extendSession(token);
int fileId = comandoJson.getInt("load");
JsonArray dependenciasJsonArray = comandoJson.getJsonArray("dependencias");
......@@ -150,6 +163,7 @@ public class CommandsBean {
Logger.getLogger(CommandsBean.class.getName()).log(Level.SEVERE, null, ex);
}
} else if (comandoJson.containsKey("restart")) {
//La extension de la sesion se realiza en restartProcess.
restartProcess(this.cedula, token, session);
}
......@@ -171,6 +185,12 @@ public class CommandsBean {
public void restartProcess(String cedula, String token, Session session) throws InterruptedException {
try {
if(!loginEJB.validarSesion(token)){
session.close(new CloseReason(CloseCodes.VIOLATED_POLICY,"Sin permisos"));
System.out.print("Web socket finalizado");
return;
}
loginEJB.extendSession(token);
this.callback = session;
this.cedula = cedula;
if (this.proceso != null && this.proceso.isAlive()) {
......@@ -239,9 +259,13 @@ public class CommandsBean {
directory = new File(fullPathMatefunTmp + this.cedula);
}
deleteDirectory(directory);
this.proceso.destroy();
this.standardConsoleThread.interrupt();
this.errorConsoleThread.interrupt();
if(this.proceso!=null && this.proceso.isAlive())
this.proceso.destroy();
if(this.standardConsoleThread != null && this.standardConsoleThread.isAlive())
this.standardConsoleThread.interrupt();
if(this.errorConsoleThread != null && this.errorConsoleThread.isAlive())
this.errorConsoleThread.interrupt();
loginEJB.deleteExpiredSessions();
}
private boolean deleteDirectory(File directory) {
......
......@@ -10,6 +10,7 @@ import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Properties;
......@@ -41,6 +42,7 @@ import edu.proygrado.modelo.Grupo;
import edu.proygrado.modelo.GrupoPK;
import edu.proygrado.modelo.Liceo;
import edu.proygrado.modelo.LiceoPK;
import edu.proygrado.modelo.Sesion;
import edu.proygrado.modelo.Usuario;
/**
......@@ -62,6 +64,48 @@ public class LoginEJB {
@EJB
private InvitadoEJB invitadoEJB;
public boolean validarSesion(String token){
Sesion sesion = em.find(Sesion.class,token);
Date now = new Date();
if(sesion != null && sesion.getTimestamp().getTime() > now.getTime()-60*60*1000){
return true;
}
return false;
}
private void updateSession(String token,Usuario usuario){
Sesion sesion = em.find(Sesion.class,token);
if(sesion == null){
sesion = new Sesion();
sesion.setToken(token);
sesion.setUsuario(usuario);
sesion.setTimestamp(new Date());
em.persist(sesion);
}else{
sesion.setTimestamp(new Date());
}
}
public void extendSession(String token){
Sesion sesion = em.find(Sesion.class,token);
if(sesion != null){
sesion.setTimestamp(new Date());
}
}
public void deleteExpiredSessions(){
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.HOUR_OF_DAY, -1);
Date horaExpiracion = cal.getTime();
List<Sesion> sesiones = em.createQuery("select s from Sesion s where s.timestamp < :horaExpiracion", Sesion.class)
.setParameter("horaExpiracion", horaExpiracion)
.getResultList();
for(Sesion sesion:sesiones){
em.remove(sesion);
}
}
public UsuarioDTO login(String cedula, String password) throws MatefunException {
Usuario usuario;
......@@ -78,6 +122,7 @@ public class LoginEJB {
System.out.println("Retorno usuario local");
System.out.println(this.toString());
String tokenAuth = generateToken();
updateSession(tokenAuth, usuario);
invitadoEJB.setUsuario(tokenAuth, usuario);
return new UsuarioDTO(tokenAuth, usuario);
}
......@@ -98,6 +143,7 @@ public class LoginEJB {
System.out.println("Credenciales locales invalidas pero validas en moodle. Retorno usuario.");
usuario.setPassword(generateHash(password));
String tokenAuth = generateToken();
updateSession(tokenAuth, usuario);
invitadoEJB.setUsuario(tokenAuth, usuario);
return new UsuarioDTO(tokenAuth, usuario);
} else {
......@@ -180,6 +226,7 @@ public class LoginEJB {
em.persist(root);
em.persist(nuevoDesdeMoodle);
String tokenAuth = generateToken();
updateSession(tokenAuth, usuario);
invitadoEJB.setUsuario(tokenAuth, nuevoDesdeMoodle);
return new UsuarioDTO(tokenAuth, nuevoDesdeMoodle);
}
......
package edu.proygrado.ejb;
import java.io.Serializable;
import edu.proygrado.modelo.Usuario;
public class Sesion implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private Usuario usuario;
public Usuario getUsuario() {
return usuario;
}
public void setUsuario(Usuario usuario) {
this.usuario = usuario;
}
}
package edu.proygrado.matefun;
import java.io.IOException;
import javax.annotation.Priority;
import javax.inject.Inject;
import javax.ws.rs.Priorities;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import edu.proygrado.ejb.LoginEJB;
@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {
@Inject
LoginEJB login;
@Override
public void filter(ContainerRequestContext context) throws IOException {
String path = context.getUriInfo().getPath();
if(path.equals("/login")){
return;
}
String authorizationHeader = context.getHeaderString(HttpHeaders.AUTHORIZATION);
// Chequear existencia de cabezal
if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
abort(context, Response.Status.UNAUTHORIZED);
return;
}
// Extrae token de HTTP Authorization header
String token = authorizationHeader.substring("Bearer ".length()).trim();
if(!login.validarSesion(token)){
abort(context, Response.Status.UNAUTHORIZED);
}else{
login.extendSession(token);
}
}
private void abort(ContainerRequestContext context, Response.Status statusCode ) {
context.abortWith(Response.status(statusCode).type(MediaType.TEXT_PLAIN)
.entity("Error de seguridad").build());
}
}
\ No newline at end of file
package edu.proygrado.modelo;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@Entity
public class Sesion {
@Id
private String token;
@Temporal(value = TemporalType.TIMESTAMP)
private Date timestamp;
@ManyToOne
private Usuario usuario;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public Date getTimestamp() {
return timestamp;
}
public void setTimestamp(Date timestamp) {
this.timestamp = timestamp;
}
public Usuario getUsuario() {
return usuario;
}
public void setUsuario(Usuario usuario) {
this.usuario = usuario;
}
}
......@@ -16,8 +16,10 @@
<class>edu.proygrado.modelo.Liceo</class>
<class>edu.proygrado.modelo.LiceoPK</class>
<class>edu.proygrado.modelo.Usuario</class>
<class>edu.proygrado.modelo.Sesion</class>
<properties>
<property name="javax.persistence.schema-generation.database.action" value="none" />
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment