2 * ============LICENSE_START====================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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====================================================
22 package org.onap.aaf.auth.oauth.facade;
24 import static org.onap.aaf.auth.layer.Result.ERR_ActionNotCompleted;
25 import static org.onap.aaf.auth.layer.Result.ERR_BadData;
26 import static org.onap.aaf.auth.layer.Result.ERR_ConflictAlreadyExists;
27 import static org.onap.aaf.auth.layer.Result.ERR_Denied;
28 import static org.onap.aaf.auth.layer.Result.ERR_NotFound;
29 import static org.onap.aaf.auth.layer.Result.ERR_NotImplemented;
30 import static org.onap.aaf.auth.layer.Result.ERR_Policy;
31 import static org.onap.aaf.auth.layer.Result.ERR_Security;
32 import static org.onap.aaf.auth.layer.Result.OK;
34 import java.security.Principal;
36 import javax.servlet.http.HttpServletRequest;
37 import javax.servlet.http.HttpServletResponse;
39 import org.onap.aaf.auth.dao.cass.OAuthTokenDAO;
40 import org.onap.aaf.auth.dao.cass.Status;
41 import org.onap.aaf.auth.dao.hl.Question;
42 import org.onap.aaf.auth.env.AuthzEnv;
43 import org.onap.aaf.auth.env.AuthzTrans;
44 import org.onap.aaf.auth.layer.Result;
45 import org.onap.aaf.auth.oauth.AAF_OAuth;
46 import org.onap.aaf.auth.oauth.mapper.Mapper;
47 import org.onap.aaf.auth.oauth.mapper.Mapper.API;
48 import org.onap.aaf.auth.oauth.service.OAuthService;
49 import org.onap.aaf.auth.oauth.service.OAuthService.GRANT_TYPE;
50 import org.onap.aaf.cadi.client.Holder;
51 import org.onap.aaf.cadi.oauth.OAuth2Principal;
52 import org.onap.aaf.cadi.principal.OAuth2FormPrincipal;
53 import org.onap.aaf.misc.env.APIException;
54 import org.onap.aaf.misc.env.Data;
55 import org.onap.aaf.misc.env.Env;
56 import org.onap.aaf.misc.env.TimeTaken;
57 import org.onap.aaf.misc.rosetta.env.RosettaDF;
58 import org.onap.aaf.misc.rosetta.env.RosettaData;
60 import aaf.v2_0.Perms;
65 * This Service Facade encapsulates the essence of the API Service can do, and provides
66 * a single created object for elements such as RosettaDF.
68 * The Responsibilities of this class are to:
69 * 1) Interact with the Service Implementation (which might be supported by various kinds of Backend Storage)
70 * 2) Validate incoming data (if applicable)
71 * 3) Convert the Service response into the right Format, and mark the Content Type
72 * a) In the future, we may support multiple Response Formats, aka JSON or XML, based on User Request.
73 * 4) Log Service info, warnings and exceptions as necessary
74 * 5) When asked by the API layer, this will create and write Error content to the OutputStream
76 * Note: This Class does NOT set the HTTP Status Code. That is up to the API layer, so that it can be
77 * clearly coordinated with the API Documentation
82 public abstract class OAFacadeImpl<TOKEN_REQ,TOKEN,INTROSPECT,ERROR>
83 extends DirectIntrospectImpl<INTROSPECT> implements OAFacade<INTROSPECT> {
84 private static final String INVALID_INPUT = "Invalid Input";
85 private final RosettaDF<TOKEN> tokenDF;
86 private final RosettaDF<TOKEN_REQ> tokenReqDF;
87 private final RosettaDF<INTROSPECT> introspectDF;
88 private final RosettaDF<ERROR> errDF;
89 public final RosettaDF<Perms> permsDF;
90 private final Mapper<TOKEN_REQ, TOKEN, INTROSPECT, ERROR> mapper;
92 public OAFacadeImpl(AAF_OAuth api,
94 Mapper<TOKEN_REQ,TOKEN,INTROSPECT,ERROR> mapper,
95 Data.TYPE dataType) throws APIException {
96 super(service, mapper);
98 AuthzEnv env = api.env;
99 (tokenReqDF = env.newDataFactory(mapper.getClass(API.TOKEN_REQ))).in(dataType).out(dataType);
100 (tokenDF = env.newDataFactory(mapper.getClass(API.TOKEN))).in(dataType).out(dataType);
101 (introspectDF = env.newDataFactory(mapper.getClass(API.INTROSPECT))).in(dataType).out(dataType);
102 (permsDF = env.newDataFactory(Perms.class)).in(dataType).out(dataType);
103 (errDF = env.newDataFactory(mapper.getClass(API.ERROR))).in(dataType).out(dataType);
106 ///////////////////////////
108 ///////////////////////////
109 public static final String CREATE_TOKEN = "createToken";
110 public static final String INTROSPECT = "introspect";
113 * @see org.onap.aaf.auth.oauth.facade.OAFacade#getToken(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletResponse, org.onap.aaf.auth.oauth.service.OAuthAPI)
116 public Result<Void> createBearerToken(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {
117 TimeTaken tt = trans.start(CREATE_TOKEN, Env.SUB|Env.ALWAYS);
121 request = mapper.tokenReqFromParams(req);
123 Data<TOKEN_REQ> rd = tokenReqDF.newData().load(req.getInputStream());
124 if (Question.willSpecialLog(trans, trans.user())) {
125 Question.logEncryptTrace(trans,rd.asString());
127 request = rd.asObject();
129 } catch (APIException e) {
130 trans.error().log(INVALID_INPUT,IN,CREATE_TOKEN);
131 return Result.err(Status.ERR_BadData,INVALID_INPUT);
134 // Already validated for Oauth2FormPrincipal
135 // Result<Void> rv = service.validate(trans,mapper.credsFromReq(request));
139 Holder<GRANT_TYPE> hgt = new Holder<GRANT_TYPE>(GRANT_TYPE.unknown);
140 Result<OAuthTokenDAO.Data> rs = service.createToken(trans,req,mapper.clientTokenReq(request,hgt),hgt);
142 if (rs.isOKhasData()) {
143 rp = mapper.tokenFromData(rs);
149 RosettaData<TOKEN> data = tokenDF.newData(trans).load(rp.value);
150 if (Question.willSpecialLog(trans, trans.user())) {
151 Question.logEncryptTrace(trans,data.asString());
153 data.to(resp.getOutputStream());
154 resp.getOutputStream().print('\n');
155 setContentType(resp,tokenDF.getOutType());
158 return Result.err(rp);
160 } catch (Exception e) {
161 trans.error().log(e,IN,CREATE_TOKEN);
162 return Result.err(e);
170 * @see org.onap.aaf.auth.oauth.facade.OAFacade#Introspect(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
173 public Result<Void> introspect(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {
174 TimeTaken tt = trans.start(INTROSPECT, Env.SUB|Env.ALWAYS);
176 Principal p = req.getUserPrincipal();
179 if (p instanceof OAuth2Principal) {
180 RosettaData<INTROSPECT> data = introspectDF.newData(trans).load(mapper.fromPrincipal((OAuth2Principal)p));
181 if (Question.willSpecialLog(trans, trans.user())) {
182 Question.logEncryptTrace(trans,data.asString());
184 data.to(resp.getOutputStream());
185 resp.getOutputStream().print('\n');
186 setContentType(resp,tokenDF.getOutType());
188 } else if (p instanceof OAuth2FormPrincipal) {
189 token = req.getParameter("token");
194 token = req.getParameter("access_token");
195 if (token==null || token.isEmpty()) {
196 token = req.getHeader("Authorization");
197 if (token != null && token.startsWith("Bearer ")) {
198 token = token.substring(7);
200 token = req.getParameter("token");
202 return Result.err(Result.ERR_Security,"token is required");
208 Result<INTROSPECT> rti = mappedIntrospect(trans,token);
211 RosettaData<INTROSPECT> data = introspectDF.newData(trans).load(rti.value);
212 if (Question.willSpecialLog(trans, trans.user())) {
213 Question.logEncryptTrace(trans,data.asString());
215 data.to(resp.getOutputStream());
216 resp.getOutputStream().print('\n');
217 setContentType(resp,tokenDF.getOutType());
220 return Result.err(rti);
222 } catch (Exception e) {
223 trans.error().log(e,IN,INTROSPECT);
224 return Result.err(e);
232 * @see com.att.authz.facade.AuthzFacade#error(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletResponse, int)
234 * Note: Conforms to AT&T TSS RESTful Error Structure
237 public void error(AuthzTrans trans, HttpServletResponse response, Result<?> result) {
238 error(trans, response, result.status,
239 result.details==null?"":result.details.trim(),
240 result.variables==null?Result.EMPTY_VARS:result.variables);
244 public void error(AuthzTrans trans, HttpServletResponse response, int status, final String _msg, final Object ... _detail) {
247 boolean hidemsg=false;
250 case ERR_ActionNotCompleted:
252 prefix = "Accepted, Action not complete";
253 response.setStatus(/*httpstatus=*/202);
261 prefix = "Forbidden";
262 response.setStatus(/*httpstatus=*/403);
268 prefix = "Not Found";
269 response.setStatus(/*httpstatus=*/404);
275 prefix = "Not Acceptable";
276 response.setStatus(/*httpstatus=*/406);
280 case ERR_ConflictAlreadyExists:
282 prefix = "Conflict Already Exists";
283 response.setStatus(/*httpstatus=*/409);
287 case ERR_NotImplemented:
289 prefix = "Not Implemented";
290 response.setStatus(/*httpstatus=*/501);
296 prefix = "General Service Error";
297 response.setStatus(/*httpstatus=*/500);
303 StringBuilder holder = new StringBuilder();
304 ERROR em = mapper.errorFromMessage(holder, msgId,prefix + ": " + _msg,_detail);
313 em = mapper.errorFromMessage(holder, msgId, "Server had an issue processing this request");
315 errDF.newData(trans).load(em).to(response.getOutputStream());
317 } catch (Exception e) {
318 trans.error().log(e,"unable to send response for",_msg);
322 public Mapper<TOKEN_REQ,TOKEN,INTROSPECT,ERROR> mapper() {
327 * @see org.onap.aaf.auth.oauth.facade.OAFacade#service()
330 public OAuthService service() {