Skip to content
Snippets Groups Projects
Commit c5edc9ae authored by Gonzalo Fabian Cameto Hernandez's avatar Gonzalo Fabian Cameto Hernandez
Browse files

Seguridad en servicios

parent 0664a5e3
No related branches found
No related tags found
No related merge requests found
Showing
with 202 additions and 43 deletions
//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>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment