Commit b1a280739c057b2aa569350d380f7d01f1bf8eb8
1 parent
fcb6b857
Segurança
Showing
6 changed files
with
246 additions
and
0 deletions
Show diff stats
jwt/pom.xml
| @@ -11,6 +11,7 @@ | @@ -11,6 +11,7 @@ | ||
| 11 | <maven.compiler.target>1.8</maven.compiler.target> | 11 | <maven.compiler.target>1.8</maven.compiler.target> |
| 12 | </properties> | 12 | </properties> |
| 13 | <dependencies> | 13 | <dependencies> |
| 14 | + | ||
| 14 | <dependency> | 15 | <dependency> |
| 15 | <groupId>${project.groupId}</groupId> | 16 | <groupId>${project.groupId}</groupId> |
| 16 | <artifactId>demoiselle-core</artifactId> | 17 | <artifactId>demoiselle-core</artifactId> |
| @@ -29,5 +30,18 @@ | @@ -29,5 +30,18 @@ | ||
| 29 | <version>${project.version}</version> | 30 | <version>${project.version}</version> |
| 30 | </dependency> | 31 | </dependency> |
| 31 | 32 | ||
| 33 | + <dependency> | ||
| 34 | + <groupId>org.bitbucket.b_c</groupId> | ||
| 35 | + <artifactId>jose4j</artifactId> | ||
| 36 | + <version>0.4.1</version> | ||
| 37 | + </dependency> | ||
| 38 | + | ||
| 39 | + <dependency> | ||
| 40 | + <groupId>com.google.code.gson</groupId> | ||
| 41 | + <artifactId>gson</artifactId> | ||
| 42 | + <version>2.2.2</version> | ||
| 43 | + <scope>compile</scope> | ||
| 44 | + </dependency> | ||
| 45 | + | ||
| 32 | </dependencies> | 46 | </dependencies> |
| 33 | </project> | 47 | </project> |
jwt/src/main/java/org/demoiselle/jee/security/jwt/impl/SecurityContextImpl.java
0 → 100644
| @@ -0,0 +1,123 @@ | @@ -0,0 +1,123 @@ | ||
| 1 | +package org.demoiselle.jee.security.jwt.impl; | ||
| 2 | + | ||
| 3 | +import org.demoiselle.jee.security.Token; | ||
| 4 | +import javax.enterprise.context.Dependent; | ||
| 5 | +import java.security.Principal; | ||
| 6 | +import java.util.Map; | ||
| 7 | +import java.util.Set; | ||
| 8 | +import javax.inject.Inject; | ||
| 9 | +import org.demoiselle.jee.core.util.ResourceBundle; | ||
| 10 | +import org.demoiselle.jee.security.interfaces.SecurityContext; | ||
| 11 | +import org.demoiselle.jee.security.exception.NotLoggedInException; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * <p> | ||
| 15 | + * This is the default implementation of {@link SecurityContext} interface. | ||
| 16 | + * </p> | ||
| 17 | + * | ||
| 18 | + * @author SERPRO | ||
| 19 | + */ | ||
| 20 | +@Dependent | ||
| 21 | +public class SecurityContextImpl implements SecurityContext { | ||
| 22 | + | ||
| 23 | + private static final long serialVersionUID = 1L; | ||
| 24 | + | ||
| 25 | + @Inject | ||
| 26 | + private TokensManager tm; | ||
| 27 | + | ||
| 28 | + @Inject | ||
| 29 | + private Token token; | ||
| 30 | + | ||
| 31 | + @Inject | ||
| 32 | + private ResourceBundle bundle; | ||
| 33 | + | ||
| 34 | + /** | ||
| 35 | + * @see org.demoiselle.security.SecurityContext#hasPermission(String, | ||
| 36 | + * String) | ||
| 37 | + */ | ||
| 38 | + @Override | ||
| 39 | + public boolean hasPermission(String resource, String operation) { | ||
| 40 | + boolean result = true; | ||
| 41 | + | ||
| 42 | + return result; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + /** | ||
| 46 | + * @see org.demoiselle.security.SecurityContext#hasRole(String) | ||
| 47 | + */ | ||
| 48 | + @Override | ||
| 49 | + public boolean hasRole(String role) { | ||
| 50 | + boolean result = true; | ||
| 51 | + | ||
| 52 | + return result; | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + /** | ||
| 56 | + * @see org.demoiselle.security.SecurityContext#isLoggedIn() | ||
| 57 | + */ | ||
| 58 | + @Override | ||
| 59 | + public boolean isLoggedIn() { | ||
| 60 | + return getUser() != null; | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + /** | ||
| 64 | + * @see org.demoiselle.security.SecurityContext#getUser() | ||
| 65 | + */ | ||
| 66 | + @Override | ||
| 67 | + public Principal getUser() { | ||
| 68 | + if (token.getKey() != null && !token.getKey().isEmpty()) { | ||
| 69 | + return tm.getUser(token.getKey()); | ||
| 70 | + } | ||
| 71 | + return token.getPrincipal(); | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + public void checkLoggedIn() throws NotLoggedInException { | ||
| 75 | + if (!isLoggedIn()) { | ||
| 76 | + throw new NotLoggedInException(bundle.getString("user-not-authenticated")); | ||
| 77 | + } | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + @Override | ||
| 81 | + public void setRoles(Set<String> roles) { | ||
| 82 | + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + @Override | ||
| 86 | + public void setPermission(Map<String, String> permissions) { | ||
| 87 | + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + @Override | ||
| 91 | + public Set<String> getResources(String operation) { | ||
| 92 | + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + @Override | ||
| 96 | + public Set<String> getOperations(String resources) { | ||
| 97 | + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + @Override | ||
| 101 | + public void setUser(Principal principal) { | ||
| 102 | + token.setKey(tm.getToken(principal)); | ||
| 103 | + token.setPrincipal(principal); | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + @Override | ||
| 107 | + public String getToken() { | ||
| 108 | + if (token.getKey() != null && token.getKey().isEmpty()) { | ||
| 109 | + token.setKey(tm.getToken(token.getPrincipal())); | ||
| 110 | + } | ||
| 111 | + return token.getKey(); | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + @Override | ||
| 115 | + public void setToken(String chave) { | ||
| 116 | + token.setPrincipal(tm.getUser(chave)); | ||
| 117 | + if (token.getPrincipal() == null) { | ||
| 118 | + throw new NotLoggedInException(bundle.getString("user-not-authenticated")); | ||
| 119 | + } | ||
| 120 | + token.setKey(chave); | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | +} |
jwt/src/main/java/org/demoiselle/jee/security/jwt/impl/TokensManager.java
0 → 100644
| @@ -0,0 +1,106 @@ | @@ -0,0 +1,106 @@ | ||
| 1 | +/* | ||
| 2 | + * To change this license header, choose License Headers in Project Properties. | ||
| 3 | + * To change this template file, choose Tools | Templates | ||
| 4 | + * and open the template in the editor. | ||
| 5 | + */ | ||
| 6 | +package org.demoiselle.jee.security.jwt.impl; | ||
| 7 | + | ||
| 8 | +import com.google.gson.Gson; | ||
| 9 | +import java.security.Key; | ||
| 10 | +import java.security.Principal; | ||
| 11 | +import java.util.Map; | ||
| 12 | +import java.util.UUID; | ||
| 13 | +import java.util.logging.Level; | ||
| 14 | +import java.util.logging.Logger; | ||
| 15 | +import javax.annotation.PostConstruct; | ||
| 16 | +import javax.enterprise.context.RequestScoped; | ||
| 17 | +import javax.inject.Inject; | ||
| 18 | +import javax.servlet.http.HttpServletRequest; | ||
| 19 | +import javax.ws.rs.container.PreMatching; | ||
| 20 | +import org.jose4j.jwk.RsaJsonWebKey; | ||
| 21 | +import org.jose4j.jwk.RsaJwkGenerator; | ||
| 22 | +import org.jose4j.jws.AlgorithmIdentifiers; | ||
| 23 | +import org.jose4j.jws.JsonWebSignature; | ||
| 24 | +import org.jose4j.jwt.JwtClaims; | ||
| 25 | +import org.jose4j.jwt.consumer.InvalidJwtException; | ||
| 26 | +import org.jose4j.jwt.consumer.JwtConsumer; | ||
| 27 | +import org.jose4j.jwt.consumer.JwtConsumerBuilder; | ||
| 28 | +import org.jose4j.lang.JoseException; | ||
| 29 | + | ||
| 30 | +/** | ||
| 31 | + * | ||
| 32 | + * @author 70744416353 | ||
| 33 | + */ | ||
| 34 | +@RequestScoped | ||
| 35 | +public class TokensManager { | ||
| 36 | + | ||
| 37 | + @Inject | ||
| 38 | + private HttpServletRequest httpRequest; | ||
| 39 | + | ||
| 40 | + private RsaJsonWebKey rsaJsonWebKey; | ||
| 41 | + | ||
| 42 | + @Inject | ||
| 43 | + private Logger logger; | ||
| 44 | + | ||
| 45 | + public void TokensManager() throws JoseException { | ||
| 46 | + RsaJsonWebKey chave = RsaJwkGenerator.generateJwk(2048); | ||
| 47 | + logger.info("Se você quiser usar sua app em cluster, coloque o parametro jwt.key no app.properties e reinicie a aplicacao"); | ||
| 48 | + logger.log(Level.INFO, "jwt.key={0}", chave); | ||
| 49 | + 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 "); | ||
| 50 | + rsaJsonWebKey = (RsaJsonWebKey) RsaJsonWebKey.Factory.newPublicJwk((Key) chave); | ||
| 51 | + rsaJsonWebKey.setKeyId("demoiselle-security-jwt"); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + public Principal getUser(String jwt) { | ||
| 55 | + Principal usuario = null; | ||
| 56 | + if (jwt != null && !jwt.isEmpty()) { | ||
| 57 | + JwtConsumer jwtConsumer = new JwtConsumerBuilder() | ||
| 58 | + .setRequireExpirationTime() // the JWT must have an expiration time | ||
| 59 | + .setAllowedClockSkewInSeconds(60) // allow some leeway in validating time based claims to account for clock skew | ||
| 60 | + .setExpectedIssuer("demoiselle") // whom the JWT needs to have been issued by | ||
| 61 | + .setExpectedAudience("demoiselle") // to whom the JWT is intended for | ||
| 62 | + .setVerificationKey(rsaJsonWebKey.getKey()) // verify the signature with the public key | ||
| 63 | + .build(); // create the JwtConsumer instance | ||
| 64 | + | ||
| 65 | + try { | ||
| 66 | + JwtClaims jwtClaims = jwtConsumer.processToClaims(jwt); | ||
| 67 | + usuario = new Gson().fromJson((String) jwtClaims.getClaimValue("user"), Principal.class); | ||
| 68 | + | ||
| 69 | + String ip = httpRequest.getRemoteAddr(); | ||
| 70 | + if (!ip.equalsIgnoreCase((String) jwtClaims.getClaimValue("ip"))) { | ||
| 71 | + usuario = null; | ||
| 72 | + } | ||
| 73 | + } catch (InvalidJwtException e) { | ||
| 74 | + //Logger.getLogger(TokenRepository.class.getName()).log(Level.SEVERE, null, e); | ||
| 75 | + } | ||
| 76 | + } | ||
| 77 | + return usuario; | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + public String getToken(Principal user) { | ||
| 81 | + try { | ||
| 82 | + JwtClaims claims = new JwtClaims(); | ||
| 83 | + claims.setIssuer("demoiselle"); | ||
| 84 | + claims.setAudience("demoiselle"); | ||
| 85 | + claims.setExpirationTimeMinutesInTheFuture(720); | ||
| 86 | + claims.setGeneratedJwtId(); | ||
| 87 | + claims.setIssuedAtToNow(); | ||
| 88 | + claims.setNotBeforeMinutesInThePast(1); | ||
| 89 | + | ||
| 90 | + claims.setClaim("ip", httpRequest.getRemoteAddr()); | ||
| 91 | + claims.setClaim("user", new Gson().toJson(user)); | ||
| 92 | + | ||
| 93 | + JsonWebSignature jws = new JsonWebSignature(); | ||
| 94 | + jws.setPayload(claims.toJson()); | ||
| 95 | + jws.setKey(rsaJsonWebKey.getPrivateKey()); | ||
| 96 | + jws.setKeyIdHeaderValue(rsaJsonWebKey.getKeyId()); | ||
| 97 | + jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256); | ||
| 98 | + return jws.getCompactSerialization(); | ||
| 99 | + } catch (JoseException ex) { | ||
| 100 | + logger.severe(ex.getMessage()); | ||
| 101 | + } | ||
| 102 | + return null; | ||
| 103 | + | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | +} |
pom.xml
| @@ -31,6 +31,7 @@ | @@ -31,6 +31,7 @@ | ||
| 31 | <!--<module>swagger</module>--> | 31 | <!--<module>swagger</module>--> |
| 32 | <module>security</module> | 32 | <module>security</module> |
| 33 | <module>basic</module> | 33 | <module>basic</module> |
| 34 | + <module>jwt</module> | ||
| 34 | </modules> | 35 | </modules> |
| 35 | 36 | ||
| 36 | <dependencyManagement> | 37 | <dependencyManagement> |