diff --git a/Frontend Angular 4/src/app/shared/config.ts b/Frontend Angular 4/src/app/shared/config.ts
index 1f030693618757283b799815428add96d54fcfcd..e5b48168ac6ac14bb205b1a53d1043eec5ae2f16 100644
--- a/Frontend Angular 4/src/app/shared/config.ts	
+++ b/Frontend Angular 4/src/app/shared/config.ts	
@@ -1,9 +1,9 @@
 //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';
diff --git a/Frontend Angular 4/src/app/shared/services/authentication.service.ts b/Frontend Angular 4/src/app/shared/services/authentication.service.ts
index 8967c6f5b671774b1475fb2ee26bbe4d06895c9b..972b2469cab65df9990f0d4c66fa9cdd5aebe7c5 100644
--- a/Frontend Angular 4/src/app/shared/services/authentication.service.ts	
+++ b/Frontend Angular 4/src/app/shared/services/authentication.service.ts	
@@ -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));
             });
     }
 
diff --git a/Frontend Angular 4/src/app/shared/services/ghci.service.ts b/Frontend Angular 4/src/app/shared/services/ghci.service.ts
index d8e0e34eae298b2c297388f7de913d3cb8ac8b44..8a24162fc5797be6d7cf3d0d5345faedec6f009d 100644
--- a/Frontend Angular 4/src/app/shared/services/ghci.service.ts	
+++ b/Frontend Angular 4/src/app/shared/services/ghci.service.ts	
@@ -1,9 +1,11 @@
 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);
 		}
 	}
diff --git a/Frontend Angular 4/src/app/shared/services/haskell.service.ts b/Frontend Angular 4/src/app/shared/services/haskell.service.ts
index 97265288dcc157ec0c5e3ce33f44e7b4fe61f186..d30b27dbd0ce9f2a21f06d4799df684765ff8259 100644
--- a/Frontend Angular 4/src/app/shared/services/haskell.service.ts	
+++ b/Frontend Angular 4/src/app/shared/services/haskell.service.ts	
@@ -1,4 +1,5 @@
 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 :
diff --git a/Frontend Angular 4/src/app/shared/services/usuario.service.ts b/Frontend Angular 4/src/app/shared/services/usuario.service.ts
index 1cce787b26cf12c698616c0a161a84f8e2fb102d..3c65e92f443e5864d0700db499102f66f2ce2f89 100644
--- a/Frontend Angular 4/src/app/shared/services/usuario.service.ts	
+++ b/Frontend Angular 4/src/app/shared/services/usuario.service.ts	
@@ -1,8 +1,10 @@
 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
diff --git a/Servidor JEE/src/main/java/edu/proygrado/ejb/CommandsBean.java b/Servidor JEE/src/main/java/edu/proygrado/ejb/CommandsBean.java
index b9d2c7c1faf1eb4e7da47b91957d19e7c34cbc23..6f01fb8a3789c5b2c75dbee2c633e401c94b891c 100644
--- a/Servidor JEE/src/main/java/edu/proygrado/ejb/CommandsBean.java	
+++ b/Servidor JEE/src/main/java/edu/proygrado/ejb/CommandsBean.java	
@@ -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) {
diff --git a/Servidor JEE/src/main/java/edu/proygrado/ejb/LoginEJB.java b/Servidor JEE/src/main/java/edu/proygrado/ejb/LoginEJB.java
index b5afe2eb70723cafe360d2896610d8df34d81db6..ab747f39a80d36f60f5c7c1dfe05b19847903bba 100644
--- a/Servidor JEE/src/main/java/edu/proygrado/ejb/LoginEJB.java	
+++ b/Servidor JEE/src/main/java/edu/proygrado/ejb/LoginEJB.java	
@@ -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);
 		}
diff --git a/Servidor JEE/src/main/java/edu/proygrado/ejb/Sesion.java b/Servidor JEE/src/main/java/edu/proygrado/ejb/Sesion.java
deleted file mode 100644
index 4b232af985f5f56b40a0fed168aca2158ae697c6..0000000000000000000000000000000000000000
--- a/Servidor JEE/src/main/java/edu/proygrado/ejb/Sesion.java	
+++ /dev/null
@@ -1,23 +0,0 @@
-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;
-	}
-		
-}
diff --git a/Servidor JEE/src/main/java/edu/proygrado/matefun/AuthenticationFilter.java b/Servidor JEE/src/main/java/edu/proygrado/matefun/AuthenticationFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..e8eb3aeca897a8580602a5ef1ac5a1495b7a2458
--- /dev/null
+++ b/Servidor JEE/src/main/java/edu/proygrado/matefun/AuthenticationFilter.java	
@@ -0,0 +1,57 @@
+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
diff --git a/Servidor JEE/src/main/java/edu/proygrado/modelo/Sesion.java b/Servidor JEE/src/main/java/edu/proygrado/modelo/Sesion.java
new file mode 100644
index 0000000000000000000000000000000000000000..19d56752242e074f9377e6e9e0b5c8e4bf65e01b
--- /dev/null
+++ b/Servidor JEE/src/main/java/edu/proygrado/modelo/Sesion.java	
@@ -0,0 +1,41 @@
+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;
+	}
+	
+}
diff --git a/Servidor JEE/src/main/resources/META-INF/persistence.xml b/Servidor JEE/src/main/resources/META-INF/persistence.xml
index 2eb2226f5dd2d74649816e3979e32f480cbaf6c4..def388faad41ec461bf1a04851ccdf78b4a5d107 100644
--- a/Servidor JEE/src/main/resources/META-INF/persistence.xml	
+++ b/Servidor JEE/src/main/resources/META-INF/persistence.xml	
@@ -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>