Update oauth-provider to use new OSGi APIs
[ccsdk/features.git] / sdnr / wt / oauth-provider / provider-jar / src / main / java / org / onap / ccsdk / features / sdnr / wt / oauthprovider / providers / TokenCreator.java
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP : ccsdk features
4  * ================================================================================
5  * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property.
6  * All rights reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  *
21  */
22 package org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers;
23
24 import com.auth0.jwt.JWT;
25 import com.auth0.jwt.algorithms.Algorithm;
26 import com.auth0.jwt.exceptions.JWTDecodeException;
27 import com.auth0.jwt.exceptions.JWTVerificationException;
28 import com.auth0.jwt.interfaces.DecodedJWT;
29 import com.auth0.jwt.interfaces.JWTVerifier;
30 import java.io.IOException;
31 import java.security.Security;
32 import java.util.Arrays;
33 import java.util.Date;
34 import java.util.Optional;
35 import javax.servlet.http.Cookie;
36 import javax.servlet.http.HttpServletRequest;
37 import org.bouncycastle.jce.provider.BouncyCastleProvider;
38 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.Config;
39 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.UserTokenPayload;
40 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.AuthHttpServlet;
41 import org.apache.shiro.authc.BearerToken;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 public class TokenCreator {
46
47     private static final Logger LOG = LoggerFactory.getLogger(AuthHttpServlet.class.getName());
48     private final String issuer;
49     private static TokenCreator _instance;
50     private final long tokenLifetimeSeconds;
51     private final Algorithm algorithm;
52
53     private static final String ROLES_CLAIM = "roles";
54     private static final String FAMILYNAME_CLAIM = "family_name";
55     private static final String NAME_CLAIM = "name";
56     private static final String PROVIDERID_CLAIM = "provider_id";
57     private static final String COOKIE_NAME_AUTH = "token";
58
59     static {
60         Security.addProvider(
61                 new BouncyCastleProvider()
62        );
63     }
64     public static TokenCreator getInstance(Config config) throws IllegalArgumentException, IOException {
65         if (_instance == null) {
66             _instance = new TokenCreator(config);
67         }
68         return _instance;
69     }
70
71     public static TokenCreator getInstance(String alg, String secret, String issuer, long tokenLifetime)
72             throws IllegalArgumentException, IOException {
73         return getInstance(alg, secret, null, issuer, tokenLifetime);
74     }
75
76     public static TokenCreator getInstance(String alg, String secret, String pubkey, String issuer, long tokenLifetime)
77             throws IllegalArgumentException, IOException {
78         if (_instance == null) {
79             _instance = new TokenCreator(alg, secret, pubkey, issuer, tokenLifetime);
80         }
81         return _instance;
82     }
83
84     private TokenCreator(Config config) throws IllegalArgumentException, IOException {
85         this(config.getAlgorithm(), config.getTokenSecret(), config.getPublicKey(), config.getTokenIssuer(),
86                 config.getTokenLifetime());
87     }
88
89     private TokenCreator(String alg, String secret, String pubkey, String issuer, long tokenLifetime)
90             throws IllegalArgumentException, IOException {
91         this.issuer = issuer;
92         this.tokenLifetimeSeconds = tokenLifetime;
93         this.algorithm = this.createAlgorithm(alg, secret, pubkey);
94     }
95
96     private Algorithm createAlgorithm(String alg, String secret, String pubkey)
97             throws IllegalArgumentException, IOException {
98         if (alg == null) {
99             alg = Config.TOKENALG_HS256;
100         }
101         switch (alg) {
102             case Config.TOKENALG_HS256:
103                 return Algorithm.HMAC256(secret);
104             case Config.TOKENALG_RS256:
105                 return Algorithm.RSA256(RSAKeyReader.getPublicKey(pubkey), RSAKeyReader.getPrivateKey(secret));
106             case Config.TOKENALG_RS512:
107                 return Algorithm.RSA512(RSAKeyReader.getPublicKey(pubkey), RSAKeyReader.getPrivateKey(secret));
108             case Config.TOKENALG_CLIENT_RS256:
109                 return Algorithm.RSA256(RSAKeyReader.getPublicKey(pubkey), null);
110             case Config.TOKENALG_CLIENT_RS512:
111                 return Algorithm.RSA512(RSAKeyReader.getPublicKey(pubkey), null);
112         }
113         throw new IllegalArgumentException(String.format("unable to find algorithm for %s", alg));
114
115     }
116
117     public BearerToken createNewJWT(UserTokenPayload data) {
118         final String token = JWT.create().withIssuer(issuer).withExpiresAt(new Date(data.getExp()))
119                 .withIssuedAt(new Date(data.getIat())).withSubject(data.getPreferredUsername())
120                 .withClaim(NAME_CLAIM, data.getGivenName()).withClaim(FAMILYNAME_CLAIM, data.getFamilyName())
121                 .withClaim(PROVIDERID_CLAIM, data.getProviderId())
122                 .withArrayClaim(ROLES_CLAIM, data.getRoles().toArray(new String[data.getRoles().size()]))
123                 .sign(this.algorithm);
124         LOG.trace("token created: {}", token);
125         return new BearerToken(token);
126     }
127
128     public DecodedJWT verify(String token) {
129         DecodedJWT jwt = null;
130         LOG.debug("try to verify token {}", token);
131         try {
132             JWTVerifier verifier = JWT.require(this.algorithm).withIssuer(issuer).build();
133             jwt = verifier.verify(token);
134
135         } catch (JWTVerificationException e) {
136             LOG.warn("unable to verify token {}:", token, e);
137         }
138         return jwt;
139     }
140
141     public long getDefaultExp() {
142         return new Date().getTime() + (this.tokenLifetimeSeconds * 1000);
143     }
144
145     public long getDefaultExp(long expIn) {
146         return new Date().getTime() + expIn;
147     }
148
149     public long getDefaultIat() {
150         return new Date().getTime();
151     }
152
153     public String getBearerToken(HttpServletRequest req) {
154         return this.getBearerToken(req, false);
155     }
156
157     public String getBearerToken(HttpServletRequest req, boolean checkCookie) {
158         final String authHeader = req.getHeader("Authorization");
159         if ((authHeader == null || !authHeader.startsWith("Bearer")) && checkCookie) {
160             if(req!=null) {
161                 Cookie[] cookies = req.getCookies();
162                 Optional<Cookie> ocookie = Optional.empty();
163                 if (cookies != null) {
164                     ocookie = Arrays.stream(cookies).filter(c -> c != null && COOKIE_NAME_AUTH.equals(c.getName()))
165                             .findFirst();
166                 }
167                 if (ocookie.isEmpty()) {
168                     return null;
169                 }
170                 return ocookie.get().getValue();
171             }
172         }
173         return authHeader.substring(7);
174     }
175
176     public UserTokenPayload decode(HttpServletRequest req) throws JWTDecodeException {
177         final String token = this.getBearerToken(req);
178         return token != null ? this.decode(token) : null;
179     }
180
181     public UserTokenPayload decode(String token) {
182         if (token == null) {
183             return null;
184         }
185         DecodedJWT jwt = JWT.decode(token);
186         UserTokenPayload data = new UserTokenPayload();
187         data.setRoles(Arrays.asList(jwt.getClaim(ROLES_CLAIM).asArray(String.class)));
188         data.setExp(jwt.getExpiresAt().getTime());
189         data.setFamilyName(jwt.getClaim(FAMILYNAME_CLAIM).asString());
190         data.setGivenName(jwt.getClaim(NAME_CLAIM).asString());
191         data.setPreferredUsername(jwt.getClaim(NAME_CLAIM).asString());
192         data.setProviderId(jwt.getClaim(PROVIDERID_CLAIM).asString());
193         return data;
194     }
195
196     public Cookie createAuthCookie(BearerToken data) {
197         Cookie cookie = new Cookie(COOKIE_NAME_AUTH, data.getToken());
198         cookie.setMaxAge((int) this.tokenLifetimeSeconds);
199         cookie.setPath("/");
200         cookie.setHttpOnly(true);
201         cookie.setSecure(true);
202         return cookie;
203     }
204 }