· 7 years ago · May 21, 2018, 10:56 AM
1package com.archilleuswebservice.service.security.impl;
2
3
4import java.security.Key;
5import java.util.ArrayList;
6import java.util.Collection;
7import java.util.Date;
8import java.util.HashSet;
9import java.util.LinkedHashMap;
10import java.util.List;
11import java.util.Map;
12import java.util.Set;
13import java.util.TreeMap;
14import java.util.Map.Entry;
15
16import javax.crypto.spec.SecretKeySpec;
17import javax.xml.bind.DatatypeConverter;
18
19import com.archilleuswebservice.exceptions.security.JWTTokenExpired;
20import com.archilleuswebservice.model.Token;
21import com.archilleuswebservice.model.organizationalStructure.Company;
22import com.archilleuswebservice.model.organizationalStructure.User;
23import com.archilleuswebservice.model.organizationalStructure.UserRole;
24import com.archilleuswebservice.service.security.JWTService;
25
26import io.jsonwebtoken.Claims;
27import io.jsonwebtoken.JwtBuilder;
28import io.jsonwebtoken.Jwts;
29import io.jsonwebtoken.MalformedJwtException;
30import io.jsonwebtoken.SignatureAlgorithm;
31import io.jsonwebtoken.SignatureException;
32import io.jsonwebtoken.UnsupportedJwtException;
33
34public class JWTServiceImpl implements JWTService {
35 private short expirationHours;
36 private String secretKey;
37 private String issuer;
38
39 public JWTServiceImpl(String secretKey, String issuer) {
40 super();
41 this.secretKey = secretKey;
42 this.issuer = issuer;
43 }
44
45 /**
46 * Metoda pravi JWT token na osnovu zadatog korisnika
47 * Token potpisuje sa HS256
48 * Kljuc je definisan u dispatcher-servlet.xml
49 */
50 public Token generateTooken(final User user) {
51 if(user==null)
52 return null;
53
54 /*
55 * Prodji kroz sve role korisnika ako postoje i setuj naziv na null
56 * kako bi token zauzeo manje mesta
57 */
58 if(user.getRoles()!=null && !user.getRoles().isEmpty()){
59 for (UserRole role : user.getRoles()) {
60 role.setName(null);
61 }
62 }
63
64 //odradi algoritam za potpisivanje
65 SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
66
67 long nowMillis = System.currentTimeMillis();
68 Date now = new Date(nowMillis);
69
70 byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(secretKey);
71 Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
72
73
74 JwtBuilder builder = Jwts.builder().setId(user.getUserName())
75 .setIssuedAt(now)
76 .setSubject(user.getUserName())
77 .setIssuer(issuer)
78 .setClaims(new TreeMap<String, Object>(){{
79 put("companyId", 1);
80 put("userId", 1);
81 put("roles",user.getRoles());
82 }})
83 .signWith(signatureAlgorithm, signingKey);
84
85 //konvertuj sate za koliko istice token u milisekunde
86 int ttlMillis = expirationHours*3600000;
87 //postavi vreme kada istice tooken
88 long expMillis = nowMillis + ttlMillis;
89 Date exp = new Date(expMillis);
90 builder.setExpiration(exp);
91
92 return new Token(user, builder.compact(),expMillis);
93 }
94
95 /**
96 * Metoda dekoduje potpisan token i od njega vraca komapniju
97 * Ukoliko nesto sa tokenom nije u redu izbacice izuzetak
98 * return {@ User}
99 */
100 public User decodeTooken(String tooken) throws UnsupportedJwtException, SignatureException, JWTTokenExpired, MalformedJwtException {
101 Claims claims = Jwts.parser()
102 .setSigningKey(DatatypeConverter.parseBase64Binary(secretKey))
103 .parseClaimsJws(tooken).getBody();
104
105 Date now = new Date(System.currentTimeMillis());
106 Date expiration = claims.getExpiration();
107
108 // proveri da li je token istekao
109 if(expiration.compareTo(now)==-1)
110 throw new JWTTokenExpired();
111
112 // proveri da li token sadrzi sva obavezna polja o korisniku
113 if(claims.get("companyId")==null || ((Integer) claims.get("companyId"))<=0 || claims.get("userId")==null || ((Integer)claims.get("userId"))<=0)
114 throw new SignatureException("Token ne sadrzi id korisnika");
115
116 // kreiraj user-a na osnovu podataka izvucenih dekripcijom tookena
117 User user = new User(new Company(((Integer)claims.get("companyId")).shortValue()) , ((Integer)claims.get("userId")).shortValue());
118
119 // Izvuci iz polja roles podatke o rolama koje korisnik poseduje
120 if(claims.get("roles")!=null){
121 List<LinkedHashMap<String, String>> list = (List<LinkedHashMap<String, String>>) claims.get("roles");
122 Set<UserRole> roles = new HashSet<UserRole>();
123
124 if(list!=null && !list.isEmpty()){
125 for (LinkedHashMap<String, String> map : list)
126 if(map!=null)
127 roles.add(new UserRole(map.get("ident")));
128 user.setRoles(roles);
129 }
130 }
131
132 return user;
133 }
134
135 public void setExpirationHours(short expirationHours) {
136 this.expirationHours = expirationHours;
137 }
138
139 public Token refreshToken(String token) throws UnsupportedJwtException, SignatureException, JWTTokenExpired {
140 if(token==null || token.isEmpty())
141 throw new SignatureException("Nepostojeci token");
142
143 return generateTooken(decodeTooken(token));
144 }
145
146
147}