AT&T 2.0.19 Code drop, stage 3
[aaf/authz.git] / auth / auth-oauth / src / main / java / org / onap / aaf / auth / oauth / DirectOAuthTAF.java
1 /**
2  * ============LICENSE_START====================================================
3  * org.onap.aaf
4  * ===========================================================================
5  * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
6  * ===========================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END====================================================
19  *
20  */
21
22 package org.onap.aaf.auth.oauth;
23
24 import java.io.IOException;
25 import java.security.GeneralSecurityException;
26 import java.security.NoSuchAlgorithmException;
27 import java.util.Map;
28
29 import javax.servlet.http.HttpServletRequest;
30 import javax.servlet.http.HttpServletResponse;
31
32 import org.onap.aaf.auth.dao.hl.Question;
33 import org.onap.aaf.auth.direct.DirectAAFUserPass;
34 import org.onap.aaf.auth.env.AuthzEnv;
35 import org.onap.aaf.auth.env.AuthzTrans;
36 import org.onap.aaf.auth.layer.Result;
37 import org.onap.aaf.auth.oauth.facade.DirectIntrospect;
38 import org.onap.aaf.auth.rserv.TransFilter;
39 import org.onap.aaf.cadi.CachedPrincipal;
40 import org.onap.aaf.cadi.CadiException;
41 import org.onap.aaf.cadi.Hash;
42 import org.onap.aaf.cadi.LocatorException;
43 import org.onap.aaf.cadi.PropAccess;
44 import org.onap.aaf.cadi.CachedPrincipal.Resp;
45 import org.onap.aaf.cadi.CredVal.Type;
46 import org.onap.aaf.cadi.Taf.LifeForm;
47 import org.onap.aaf.cadi.config.Config;
48 import org.onap.aaf.cadi.oauth.OAuth2HttpTafResp;
49 import org.onap.aaf.cadi.oauth.OAuth2Principal;
50 import org.onap.aaf.cadi.oauth.TokenClient;
51 import org.onap.aaf.cadi.oauth.TokenClientFactory;
52 import org.onap.aaf.cadi.oauth.TokenMgr;
53 import org.onap.aaf.cadi.oauth.TokenPerm;
54 import org.onap.aaf.cadi.oauth.TokenMgr.TokenPermLoader;
55 import org.onap.aaf.cadi.principal.OAuth2FormPrincipal;
56 import org.onap.aaf.cadi.taf.HttpTaf;
57 import org.onap.aaf.cadi.taf.TafResp;
58 import org.onap.aaf.cadi.taf.TafResp.RESP;
59 import org.onap.aaf.cadi.util.Split;
60 import org.onap.aaf.misc.env.APIException;
61
62 import aafoauth.v2_0.Introspect;
63
64 public class DirectOAuthTAF implements HttpTaf {
65         private PropAccess access;
66         private DirectIntrospect<Introspect> oaFacade;
67         private TokenMgr tkMgr;
68         private final DirectAAFUserPass directUserPass;
69         private TokenClient altIntrospectClient;
70
71         public DirectOAuthTAF(AuthzEnv env, Question q,  DirectIntrospect<Introspect> facade) throws APIException, CadiException {
72                 access = env.access();
73                 oaFacade = facade;
74                 tkMgr = TokenMgr.getInstance(access,"dbToken","dbIntrospect");
75                 String alt_url = access.getProperty(Config.AAF_ALT_OAUTH2_INTROSPECT_URL,null);
76                 TokenClientFactory tcf;
77                 if(alt_url!=null) {
78                         try {
79                                 tcf = TokenClientFactory.instance(access);
80                                 String[] split = Split.split(',', alt_url);
81                                 int timeout = split.length>1?Integer.parseInt(split[1]):3000;
82                                 altIntrospectClient = tcf.newClient(split[0], timeout);
83                                 altIntrospectClient.client_creds(access.getProperty(Config.AAF_ALT_CLIENT_ID,null), 
84                                                                                    access.getProperty(Config.AAF_ALT_CLIENT_SECRET,null));
85                         } catch (GeneralSecurityException | IOException | LocatorException e) {
86                                 throw new CadiException(e);
87                         }
88                 }
89
90                 directUserPass = new DirectAAFUserPass(env,q);
91         }
92
93         @Override
94         public TafResp validate(LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {
95                 String value;
96                 String token;
97                 if((value=req.getHeader("Authorization"))!=null && value.startsWith("Bearer ")) {
98                         token = value.substring(7);
99                 } else {
100                         token = null;
101                 }
102
103                 if("application/x-www-form-urlencoded".equals(req.getContentType())) {
104                         Map<String, String[]> map = req.getParameterMap();
105                         String client_id=null,client_secret=null,username=null,password=null;
106                         for(Map.Entry<String, String[]> es : map.entrySet()) {
107                                 switch(es.getKey()) {
108                                         case "client_id":
109                                                 for(String s : es.getValue()) {
110                                                         client_id=s;
111                                                 }
112                                                 break;
113                                         case "client_secret":
114                                                 for(String s : es.getValue()) {
115                                                         client_secret=s;
116                                                 }
117                                                 break;
118                                         case "username":
119                                                 for(String s : es.getValue()) {
120                                                         username=s;
121                                                 }
122                                                 break;
123                                         case "password":
124                                                 for(String s : es.getValue()) {
125                                                         password=s;
126                                                 }
127                                                 break;
128                                         case "token": 
129                                                 if(token!=null) { // Defined as both Bearer and Form Encoded - Error
130                                                         return new OAuth2HttpTafResp(access, null, "Token Info found as both Bearer Token and Form Info", RESP.FAIL, resp, true);
131                                                 }
132                                                 for(String s : es.getValue()) {
133                                                         token=s;
134                                                 }
135                                                 break;
136                                         // Ignore others
137                                 }
138                         }
139                         
140                         if(client_id==null && client_secret==null) {
141                                 return new OAuth2HttpTafResp(access, null, "client_id and client_secret required", RESP.TRY_ANOTHER_TAF, resp, false);
142                         }
143                         
144                         if(token==null) { // No Token to work with, use only Client_ID and Client_Secret 
145                                 AuthzTrans trans = (AuthzTrans)req.getAttribute(TransFilter.TRANS_TAG);
146
147                                 if(directUserPass.validate(client_id, Type.PASSWORD, client_secret.getBytes(), trans)) {
148                                         // Client_ID is valid
149                                         if(username==null) { // Validating just the Client_ID
150                                                 return new OAuth2FormHttpTafResp(access,new OAuth2FormPrincipal(client_id,client_id),"OAuth client_id authenticated",RESP.IS_AUTHENTICATED,resp,false);
151                                         } else {
152                                                 //TODO - Does a clientID need specific Authorization to pair authentication with user name?  At the moment, no.
153                                                 // username is ok.
154                                                 if(password!=null) {
155                                                         if(directUserPass.validate(username, Type.PASSWORD, password.getBytes(), trans)) {
156                                                                 return new OAuth2FormHttpTafResp(access,new OAuth2FormPrincipal(client_id, username),"OAuth username authenticated",RESP.IS_AUTHENTICATED,resp,false);
157                                                         } else {
158                                                                 return new OAuth2HttpTafResp(access,null,"OAuth username " + username + " not authenticated ",RESP.FAIL,resp,true);
159                                                         }
160                                                 } else { // no Password
161                                                         //TODO Check for Trust Permission, which requires looking up Perms?
162                                                         return new OAuth2HttpTafResp(access,null,"OAuth username " + username + " not authenticated ",RESP.FAIL,resp,true);
163                                                 }
164                                         }
165                                 } else {
166                                         return new OAuth2HttpTafResp(access,null,"OAuth client_id " + client_id + " not authenticated ",RESP.FAIL,resp,true);
167                                 }
168                         }
169                 } 
170                 
171                 // OK, have only a Token to validate
172                 if(token!=null) {
173                         AuthzTrans trans = (AuthzTrans)req.getAttribute(TransFilter.TRANS_TAG);
174
175                         try {
176                                 Result<Introspect> ri = oaFacade.mappedIntrospect(trans, token);
177                                 if(ri.isOK()) {
178                                         TokenPerm tp = tkMgr.putIntrospect(ri.value, Hash.hashSHA256(token.getBytes()));
179                                         if(tp==null) {
180                                                 return new OAuth2HttpTafResp(access, null, "TokenPerm persistence failure", RESP.FAIL, resp, false);
181                                         } else {
182                                                 return new OAuth2HttpTafResp(access,new OAuth2Principal(tp,Hash.hashSHA256(token.getBytes())),"Token Authenticated",RESP.IS_AUTHENTICATED,resp,false);
183                                         }
184                                 } else {
185                                         return new OAuth2HttpTafResp(access, null, ri.errorString(), RESP.FAIL, resp, false);
186                                 }
187                         } catch (APIException e) {
188                                 trans.error().log(e,"Error getting token");
189                                 return new OAuth2HttpTafResp(access, null, "Error getting token: " + e.getMessage(), RESP.TRY_ANOTHER_TAF, resp, false);
190                         } catch (NoSuchAlgorithmException e) {
191                                 return new OAuth2HttpTafResp(access, null, "Error in security algorithm: " + e.getMessage(), RESP.TRY_ANOTHER_TAF, resp, false);
192                         }
193                 }
194                 return new OAuth2HttpTafResp(access, null, "No OAuth2 Credentials in OAuthForm", RESP.TRY_ANOTHER_TAF, resp, false);
195         }
196
197         @Override
198         public Resp revalidate(CachedPrincipal prin, Object state) {
199                 // TODO Auto-generated method stub
200                 return null;
201         }
202
203         class ServiceTPL implements TokenPermLoader {
204                 private final AuthzTrans trans;
205                 public ServiceTPL(AuthzTrans atrans) {
206                         trans = atrans;
207                 }
208                 
209                 @Override
210                 public org.onap.aaf.cadi.client.Result<TokenPerm> load(String accessToken, byte[] cred) throws APIException, CadiException, LocatorException {
211                         Result<Introspect> ri = oaFacade.mappedIntrospect(trans, accessToken);
212                         if(ri.notOK()) {
213                                 //TODO what should the status mapping be?
214                                 return org.onap.aaf.cadi.client.Result.err(ri.status,ri.errorString());
215                         }
216                         return org.onap.aaf.cadi.client.Result.ok(200,tkMgr.putIntrospect(ri.value, cred));
217                 }
218         }
219
220         public DirectAAFUserPass directUserPass() {
221                 return directUserPass;
222         }
223 }
224