From b1a280739c057b2aa569350d380f7d01f1bf8eb8 Mon Sep 17 00:00:00 2001 From: PauloGladson Date: Tue, 20 Sep 2016 18:07:26 -0300 Subject: [PATCH] Segurança --- jwt/pom.xml | 14 ++++++++++++++ jwt/src/main/java/org/demoiselle/jee/security/jwt/impl/SecurityContextImpl.java | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ jwt/src/main/java/org/demoiselle/jee/security/jwt/impl/TokensManager.java | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ jwt/src/main/resources/demoiselle.properties | 1 + jwt/src/main/resources/messages.properties | 1 + pom.xml | 1 + 6 files changed, 246 insertions(+), 0 deletions(-) create mode 100644 jwt/src/main/java/org/demoiselle/jee/security/jwt/impl/SecurityContextImpl.java create mode 100644 jwt/src/main/java/org/demoiselle/jee/security/jwt/impl/TokensManager.java create mode 100644 jwt/src/main/resources/demoiselle.properties create mode 100644 jwt/src/main/resources/messages.properties diff --git a/jwt/pom.xml b/jwt/pom.xml index cc69d6d..d3179e6 100644 --- a/jwt/pom.xml +++ b/jwt/pom.xml @@ -11,6 +11,7 @@ 1.8 + ${project.groupId} demoiselle-core @@ -29,5 +30,18 @@ ${project.version} + + org.bitbucket.b_c + jose4j + 0.4.1 + + + + com.google.code.gson + gson + 2.2.2 + compile + + diff --git a/jwt/src/main/java/org/demoiselle/jee/security/jwt/impl/SecurityContextImpl.java b/jwt/src/main/java/org/demoiselle/jee/security/jwt/impl/SecurityContextImpl.java new file mode 100644 index 0000000..cf54b35 --- /dev/null +++ b/jwt/src/main/java/org/demoiselle/jee/security/jwt/impl/SecurityContextImpl.java @@ -0,0 +1,123 @@ +package org.demoiselle.jee.security.jwt.impl; + +import org.demoiselle.jee.security.Token; +import javax.enterprise.context.Dependent; +import java.security.Principal; +import java.util.Map; +import java.util.Set; +import javax.inject.Inject; +import org.demoiselle.jee.core.util.ResourceBundle; +import org.demoiselle.jee.security.interfaces.SecurityContext; +import org.demoiselle.jee.security.exception.NotLoggedInException; + +/** + *

+ * This is the default implementation of {@link SecurityContext} interface. + *

+ * + * @author SERPRO + */ +@Dependent +public class SecurityContextImpl implements SecurityContext { + + private static final long serialVersionUID = 1L; + + @Inject + private TokensManager tm; + + @Inject + private Token token; + + @Inject + private ResourceBundle bundle; + + /** + * @see org.demoiselle.security.SecurityContext#hasPermission(String, + * String) + */ + @Override + public boolean hasPermission(String resource, String operation) { + boolean result = true; + + return result; + } + + /** + * @see org.demoiselle.security.SecurityContext#hasRole(String) + */ + @Override + public boolean hasRole(String role) { + boolean result = true; + + return result; + } + + /** + * @see org.demoiselle.security.SecurityContext#isLoggedIn() + */ + @Override + public boolean isLoggedIn() { + return getUser() != null; + } + + /** + * @see org.demoiselle.security.SecurityContext#getUser() + */ + @Override + public Principal getUser() { + if (token.getKey() != null && !token.getKey().isEmpty()) { + return tm.getUser(token.getKey()); + } + return token.getPrincipal(); + } + + public void checkLoggedIn() throws NotLoggedInException { + if (!isLoggedIn()) { + throw new NotLoggedInException(bundle.getString("user-not-authenticated")); + } + } + + @Override + public void setRoles(Set roles) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void setPermission(Map permissions) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Set getResources(String operation) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Set getOperations(String resources) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void setUser(Principal principal) { + token.setKey(tm.getToken(principal)); + token.setPrincipal(principal); + } + + @Override + public String getToken() { + if (token.getKey() != null && token.getKey().isEmpty()) { + token.setKey(tm.getToken(token.getPrincipal())); + } + return token.getKey(); + } + + @Override + public void setToken(String chave) { + token.setPrincipal(tm.getUser(chave)); + if (token.getPrincipal() == null) { + throw new NotLoggedInException(bundle.getString("user-not-authenticated")); + } + token.setKey(chave); + } + +} diff --git a/jwt/src/main/java/org/demoiselle/jee/security/jwt/impl/TokensManager.java b/jwt/src/main/java/org/demoiselle/jee/security/jwt/impl/TokensManager.java new file mode 100644 index 0000000..a0d91b7 --- /dev/null +++ b/jwt/src/main/java/org/demoiselle/jee/security/jwt/impl/TokensManager.java @@ -0,0 +1,106 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.demoiselle.jee.security.jwt.impl; + +import com.google.gson.Gson; +import java.security.Key; +import java.security.Principal; +import java.util.Map; +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.annotation.PostConstruct; +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.container.PreMatching; +import org.jose4j.jwk.RsaJsonWebKey; +import org.jose4j.jwk.RsaJwkGenerator; +import org.jose4j.jws.AlgorithmIdentifiers; +import org.jose4j.jws.JsonWebSignature; +import org.jose4j.jwt.JwtClaims; +import org.jose4j.jwt.consumer.InvalidJwtException; +import org.jose4j.jwt.consumer.JwtConsumer; +import org.jose4j.jwt.consumer.JwtConsumerBuilder; +import org.jose4j.lang.JoseException; + +/** + * + * @author 70744416353 + */ +@RequestScoped +public class TokensManager { + + @Inject + private HttpServletRequest httpRequest; + + private RsaJsonWebKey rsaJsonWebKey; + + @Inject + private Logger logger; + + public void TokensManager() throws JoseException { + RsaJsonWebKey chave = RsaJwkGenerator.generateJwk(2048); + logger.info("Se você quiser usar sua app em cluster, coloque o parametro jwt.key no app.properties e reinicie a aplicacao"); + logger.log(Level.INFO, "jwt.key={0}", chave); + logger.info("Se você não usar esse parametro, a cada reinicialização será gerada uma nova chave privada, isso inviabiliza o uso em cluster "); + rsaJsonWebKey = (RsaJsonWebKey) RsaJsonWebKey.Factory.newPublicJwk((Key) chave); + rsaJsonWebKey.setKeyId("demoiselle-security-jwt"); + } + + public Principal getUser(String jwt) { + Principal usuario = null; + if (jwt != null && !jwt.isEmpty()) { + JwtConsumer jwtConsumer = new JwtConsumerBuilder() + .setRequireExpirationTime() // the JWT must have an expiration time + .setAllowedClockSkewInSeconds(60) // allow some leeway in validating time based claims to account for clock skew + .setExpectedIssuer("demoiselle") // whom the JWT needs to have been issued by + .setExpectedAudience("demoiselle") // to whom the JWT is intended for + .setVerificationKey(rsaJsonWebKey.getKey()) // verify the signature with the public key + .build(); // create the JwtConsumer instance + + try { + JwtClaims jwtClaims = jwtConsumer.processToClaims(jwt); + usuario = new Gson().fromJson((String) jwtClaims.getClaimValue("user"), Principal.class); + + String ip = httpRequest.getRemoteAddr(); + if (!ip.equalsIgnoreCase((String) jwtClaims.getClaimValue("ip"))) { + usuario = null; + } + } catch (InvalidJwtException e) { + //Logger.getLogger(TokenRepository.class.getName()).log(Level.SEVERE, null, e); + } + } + return usuario; + } + + public String getToken(Principal user) { + try { + JwtClaims claims = new JwtClaims(); + claims.setIssuer("demoiselle"); + claims.setAudience("demoiselle"); + claims.setExpirationTimeMinutesInTheFuture(720); + claims.setGeneratedJwtId(); + claims.setIssuedAtToNow(); + claims.setNotBeforeMinutesInThePast(1); + + claims.setClaim("ip", httpRequest.getRemoteAddr()); + claims.setClaim("user", new Gson().toJson(user)); + + JsonWebSignature jws = new JsonWebSignature(); + jws.setPayload(claims.toJson()); + jws.setKey(rsaJsonWebKey.getPrivateKey()); + jws.setKeyIdHeaderValue(rsaJsonWebKey.getKeyId()); + jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256); + return jws.getCompactSerialization(); + } catch (JoseException ex) { + logger.severe(ex.getMessage()); + } + return null; + + } + +} diff --git a/jwt/src/main/resources/demoiselle.properties b/jwt/src/main/resources/demoiselle.properties new file mode 100644 index 0000000..4f777af --- /dev/null +++ b/jwt/src/main/resources/demoiselle.properties @@ -0,0 +1 @@ +user-not-authenticated \ No newline at end of file diff --git a/jwt/src/main/resources/messages.properties b/jwt/src/main/resources/messages.properties new file mode 100644 index 0000000..65893da --- /dev/null +++ b/jwt/src/main/resources/messages.properties @@ -0,0 +1 @@ +tipo-seguranca=basic \ No newline at end of file diff --git a/pom.xml b/pom.xml index 3fe8a55..2e9c6aa 100644 --- a/pom.xml +++ b/pom.xml @@ -31,6 +31,7 @@ security basic + jwt -- libgit2 0.21.2