blob: 11fc0b3f7d0b02b877ab7eb04a78463412b19ce1 [file] [log] [blame]
Michael Hanl19390652016-01-16 11:01:24 +01001package de.ids_mannheim.korap.web.service.full;
Michael Hanlfb839b92015-09-19 21:32:34 +02002
3import com.sun.jersey.spi.container.ContainerRequest;
4import com.sun.jersey.spi.container.ResourceFilters;
5import de.ids_mannheim.korap.config.*;
6import de.ids_mannheim.korap.exceptions.KustvaktException;
7import de.ids_mannheim.korap.exceptions.StatusCodes;
8import de.ids_mannheim.korap.handlers.OAuth2Handler;
9import de.ids_mannheim.korap.interfaces.AuthenticationManagerIface;
10import de.ids_mannheim.korap.interfaces.EncryptionIface;
11import de.ids_mannheim.korap.user.Attributes;
12import de.ids_mannheim.korap.user.TokenContext;
13import de.ids_mannheim.korap.user.User;
14import de.ids_mannheim.korap.utils.JsonUtils;
15import de.ids_mannheim.korap.utils.StringUtils;
16import de.ids_mannheim.korap.web.KustvaktServer;
17import de.ids_mannheim.korap.web.filter.AuthFilter;
Michael Hanl482f30d2015-09-25 12:39:46 +020018import de.ids_mannheim.korap.web.filter.BlockingFilter;
Michael Hanlfb839b92015-09-19 21:32:34 +020019import de.ids_mannheim.korap.web.filter.DefaultFilter;
20import de.ids_mannheim.korap.web.filter.PiwikFilter;
21import de.ids_mannheim.korap.web.utils.FormRequestWrapper;
Michael Hanl482f30d2015-09-25 12:39:46 +020022import de.ids_mannheim.korap.web.utils.KustvaktResponseHandler;
Michael Hanlfb839b92015-09-19 21:32:34 +020023import org.apache.oltu.oauth2.as.issuer.MD5Generator;
24import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
25import org.apache.oltu.oauth2.as.issuer.OAuthIssuerImpl;
26import org.apache.oltu.oauth2.as.request.OAuthAuthzRequest;
27import org.apache.oltu.oauth2.as.request.OAuthTokenRequest;
28import org.apache.oltu.oauth2.as.response.OAuthASResponse;
29import org.apache.oltu.oauth2.common.OAuth;
30import org.apache.oltu.oauth2.common.error.OAuthError;
31import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
32import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
33import org.apache.oltu.oauth2.common.message.OAuthResponse;
34import org.apache.oltu.oauth2.common.message.types.GrantType;
35import org.apache.oltu.oauth2.common.message.types.ResponseType;
36import org.apache.oltu.oauth2.common.message.types.TokenType;
37import org.apache.oltu.oauth2.common.utils.OAuthUtils;
38
39import javax.servlet.http.HttpServletRequest;
40import javax.servlet.http.HttpServletResponse;
41import javax.ws.rs.*;
42import javax.ws.rs.core.Context;
43import javax.ws.rs.core.MultivaluedMap;
44import javax.ws.rs.core.Response;
45import javax.ws.rs.core.SecurityContext;
46import java.net.URI;
47import java.net.URISyntaxException;
48import java.util.Collection;
49import java.util.HashMap;
50import java.util.Map;
51import java.util.Set;
52
53/**
54 * @author hanl
55 * @date 07/06/2014
56 */
57//todo: only allow oauth2 access_token requests GET methods?
58//todo: allow refresh tokens
59@Path(KustvaktServer.API_VERSION + "/oauth2")
60//@ResourceFilters({ AccessLevelFilter.class, PiwikFilter.class })
61public class OAuthService {
62
63 private OAuth2Handler handler;
64 private AuthenticationManagerIface controller;
65 private EncryptionIface crypto;
66 private KustvaktConfiguration config;
67
68 public OAuthService() {
69 this.handler = new OAuth2Handler(
70 BeanConfiguration.getBeans().getPersistenceClient());
71 this.controller = BeanConfiguration.getBeans()
72 .getAuthenticationManager();
73 this.crypto = BeanConfiguration.getBeans().getEncryption();
74 this.config = BeanConfiguration.getBeans().getConfiguration();
75 }
76
77 @POST
78 @Path("unregister")
Michael Hanl482f30d2015-09-25 12:39:46 +020079 @ResourceFilters({ AuthFilter.class, BlockingFilter.class })
Michael Hanlfb839b92015-09-19 21:32:34 +020080 public Response unregisterClient(@Context SecurityContext context,
81 @HeaderParam("Host") String host,
82 @QueryParam("client_secret") String secret,
83 @QueryParam("client_id") String client_id) {
84 ClientInfo info = new ClientInfo(client_id, secret);
85 info.setUrl(host);
86 TokenContext ctx = (TokenContext) context.getUserPrincipal();
87 try {
88 this.handler.removeClient(info,
89 this.controller.getUser(ctx.getUsername()));
90 }catch (KustvaktException e) {
Michael Hanl482f30d2015-09-25 12:39:46 +020091 throw KustvaktResponseHandler.throwit(e);
Michael Hanlfb839b92015-09-19 21:32:34 +020092 }
93 return Response.ok().build();
94 }
95
96 @POST
97 @Path("register")
Michael Hanl482f30d2015-09-25 12:39:46 +020098 @ResourceFilters({ AuthFilter.class, BlockingFilter.class })
Michael Hanlfb839b92015-09-19 21:32:34 +020099 public Response registerClient(@Context SecurityContext context,
100 @HeaderParam("Host") String host,
101 @QueryParam("redirect_url") String rurl) {
102 ClientInfo info = new ClientInfo(crypto.createID(),
103 crypto.createToken());
104 info.setUrl(host);
105 if (rurl == null)
Michael Hanl482f30d2015-09-25 12:39:46 +0200106 throw KustvaktResponseHandler
Michael Hanlfb839b92015-09-19 21:32:34 +0200107 .throwit(StatusCodes.ILLEGAL_ARGUMENT, "Missing parameter!",
108 "redirect_url");
109 info.setRedirect_uri(rurl);
110 TokenContext ctx = (TokenContext) context.getUserPrincipal();
111 try {
112 this.handler.registerClient(info,
113 this.controller.getUser(ctx.getUsername()));
114 }catch (KustvaktException e) {
Michael Hanl482f30d2015-09-25 12:39:46 +0200115 throw KustvaktResponseHandler.throwit(e);
Michael Hanlfb839b92015-09-19 21:32:34 +0200116 }
117 return Response.ok(info.toJSON()).build();
118 }
119
120 @GET
121 @Path("info")
122 @ResourceFilters({ AuthFilter.class, DefaultFilter.class,
123 PiwikFilter.class })
124 public Response getStatus(@Context SecurityContext context,
Michael Hanl19390652016-01-16 11:01:24 +0100125 @QueryParam("scope") String scopes) {
Michael Hanlfb839b92015-09-19 21:32:34 +0200126 TokenContext ctx = (TokenContext) context.getUserPrincipal();
127 User user;
128 try {
129 user = this.controller.getUser(ctx.getUsername());
130 this.controller.getUserDetails(user);
Michael Hanl19390652016-01-16 11:01:24 +0100131 Set<String> base_scope = StringUtils.toSet(scopes, " ");
Michael Hanlfb839b92015-09-19 21:32:34 +0200132 base_scope.retainAll(StringUtils.toSet(scopes));
133 scopes = StringUtils.toString(base_scope);
134 }catch (KustvaktException e) {
Michael Hanl482f30d2015-09-25 12:39:46 +0200135 throw KustvaktResponseHandler.throwit(e);
Michael Hanlfb839b92015-09-19 21:32:34 +0200136 }
137 // json format with scope callback parameter
Michael Hanl19390652016-01-16 11:01:24 +0100138 // todo: add other scopes as well!
Michael Hanlfb839b92015-09-19 21:32:34 +0200139 return Response.ok(JsonUtils.toJSON(Scopes
Michael Hanlf1e85e72016-01-21 16:55:45 +0100140 .mapScopes(scopes, user.getDetails()))).build();
Michael Hanlfb839b92015-09-19 21:32:34 +0200141 }
142
143 @GET
144 @Path("authorizations")
Michael Hanl482f30d2015-09-25 12:39:46 +0200145 @ResourceFilters({ AuthFilter.class, BlockingFilter.class })
Michael Hanlfb839b92015-09-19 21:32:34 +0200146 public Response getAuthorizations(@Context SecurityContext context,
147 @HeaderParam(ContainerRequest.USER_AGENT) String agent,
148 @HeaderParam(ContainerRequest.HOST) String host) {
149 // works on all tokens, but access to native apps cannot be revoked!
150 // check secret and id and retrieve access tokens
151 TokenContext ctx = (TokenContext) context.getUserPrincipal();
152 try {
153 User user = this.controller.getUser(ctx.getUsername());
154 Collection auths = this.handler.getAuthorizedClients(user.getId());
155 if (auths.isEmpty())
156 return Response.noContent().build();
157 return Response.ok(JsonUtils.toJSON(auths)).build();
158 }catch (KustvaktException e) {
Michael Hanl482f30d2015-09-25 12:39:46 +0200159 throw KustvaktResponseHandler.throwit(e);
Michael Hanlfb839b92015-09-19 21:32:34 +0200160 }
161 }
162
163 // todo: scopes for access_token are defined here
Michael Hanl482f30d2015-09-25 12:39:46 +0200164 // todo: if user already has an access token registered for client and application, then redirect to token endpoint to retrieve that token
Michael Hanlfb839b92015-09-19 21:32:34 +0200165 // todo: demo account should be disabled for this function --> if authentication failed, client must redirect to login url (little login window)
166 @POST
167 @Path("authorize")
168 @Consumes("application/x-www-form-urlencoded")
169 @Produces("application/json")
Michael Hanl482f30d2015-09-25 12:39:46 +0200170 @ResourceFilters({ BlockingFilter.class })
Michael Hanlfb839b92015-09-19 21:32:34 +0200171 public Response authorize(@Context HttpServletRequest request,
172 @Context SecurityContext context,
173 @HeaderParam(ContainerRequest.USER_AGENT) String agent,
174 @HeaderParam(ContainerRequest.HOST) String host,
Michael Hanlf1e85e72016-01-21 16:55:45 +0100175 MultivaluedMap<String, String> form)
Michael Hanlfb839b92015-09-19 21:32:34 +0200176 throws OAuthSystemException, URISyntaxException {
177 // user needs to be authenticated to this service!
178 TokenContext c = (TokenContext) context.getUserPrincipal();
179
180 try {
181 OAuthAuthzRequest oauthRequest = new OAuthAuthzRequest(
182 new FormRequestWrapper(request, form));
183 OAuthIssuerImpl oauthIssuerImpl = new OAuthIssuerImpl(
184 new MD5Generator());
185 User user;
186
Michael Hanlf1e85e72016-01-21 16:55:45 +0100187 Map<String, String> attr = new HashMap<>();
Michael Hanlfb839b92015-09-19 21:32:34 +0200188 attr.put(Attributes.HOST, host);
189 attr.put(Attributes.USER_AGENT, agent);
190 attr.put(Attributes.USERNAME, c.getUsername());
191 // also extractable via authorization header
192 attr.put(Attributes.CLIENT_ID, oauthRequest.getClientId());
193 attr.put(Attributes.CLIENT_SECRET, oauthRequest.getClientSecret());
194 StringBuilder scopes = new StringBuilder();
195 for (String scope : oauthRequest.getScopes())
196 scopes.append(scope + " ");
197 attr.put(Attributes.SCOPES, scopes.toString());
198
199 try {
200 user = controller.getUser(c.getUsername());
201 controller.getUserDetails(user);
202 }catch (KustvaktException e) {
Michael Hanl482f30d2015-09-25 12:39:46 +0200203 throw KustvaktResponseHandler.throwit(e);
Michael Hanlfb839b92015-09-19 21:32:34 +0200204 }
205
206 // register response according to response_type
207 String responseType = oauthRequest
208 .getParam(OAuth.OAUTH_RESPONSE_TYPE);
209
Michael Hanlfb839b92015-09-19 21:32:34 +0200210 final String authorizationCode = oauthIssuerImpl
211 .authorizationCode();
212 ClientInfo info = this.handler
213 .getClient(oauthRequest.getClientId());
214
215 if (info == null || !info.getClient_secret()
216 .equals(oauthRequest.getClientSecret())) {
217 OAuthResponse res = OAuthASResponse
218 .errorResponse(HttpServletResponse.SC_BAD_REQUEST)
219 .setError(OAuthError.CodeResponse.UNAUTHORIZED_CLIENT)
220 .setErrorDescription("Unauthorized client!\n")
221 .buildJSONMessage();
222 return Response.status(res.getResponseStatus())
223 .entity(res.getBody()).build();
224 }
225
226 if (!info.getRedirect_uri()
227 .contains(oauthRequest.getRedirectURI())) {
228 OAuthResponse res = OAuthASResponse
229 .errorResponse(HttpServletResponse.SC_BAD_REQUEST)
230 .setError(OAuthError.CodeResponse.INVALID_REQUEST)
231 .setErrorDescription("Unauthorized redirect!\n")
232 .buildJSONMessage();
233 return Response.status(res.getResponseStatus())
234 .entity(res.getBody()).build();
235 }
236
237 String accessToken = this.handler
238 .getToken(oauthRequest.getClientId(), user.getId());
Michael Hanl482f30d2015-09-25 12:39:46 +0200239
240 //todo: test correct redirect and parameters
Michael Hanlfb839b92015-09-19 21:32:34 +0200241 if (accessToken != null) {
Michael Hanl482f30d2015-09-25 12:39:46 +0200242 // fixme: correct status code?
243 OAuthASResponse.OAuthResponseBuilder builder = OAuthASResponse
244 .status(HttpServletResponse.SC_FOUND);
Michael Hanlfb839b92015-09-19 21:32:34 +0200245 final OAuthResponse response = builder.location("/oauth2/token")
246 .setParam(OAuth.OAUTH_CLIENT_ID,
247 oauthRequest.getClientId())
248 .setParam(OAuth.OAUTH_CLIENT_SECRET,
249 oauthRequest.getClientSecret())
250 .buildQueryMessage();
251 return Response.status(response.getResponseStatus())
252 .location(new URI(response.getLocationUri())).build();
253 }
254
Michael Hanl482f30d2015-09-25 12:39:46 +0200255 final OAuthResponse response;
256 String redirectURI = oauthRequest.getRedirectURI();
257 if (OAuthUtils.isEmpty(redirectURI)) {
258 throw new WebApplicationException(
259 Response.status(HttpServletResponse.SC_BAD_REQUEST)
260 .entity("OAuth callback url needs to be provided by client!!!\n")
261 .build());
262 }
263
Michael Hanlfb839b92015-09-19 21:32:34 +0200264 if (responseType.equals(ResponseType.CODE.toString())) {
Michael Hanl482f30d2015-09-25 12:39:46 +0200265 OAuthASResponse.OAuthAuthorizationResponseBuilder builder = OAuthASResponse
266 .authorizationResponse(request,
267 HttpServletResponse.SC_FOUND);
268 builder.location(redirectURI);
269
Michael Hanlfb839b92015-09-19 21:32:34 +0200270 try {
271 AuthCodeInfo codeInfo = new AuthCodeInfo(
272 info.getClient_id(), authorizationCode);
273 codeInfo.setScopes(StringUtils
274 .toString(oauthRequest.getScopes(), " "));
275 this.handler.authorize(codeInfo, user);
276 }catch (KustvaktException e) {
Michael Hanl482f30d2015-09-25 12:39:46 +0200277 throw KustvaktResponseHandler.throwit(e);
Michael Hanlfb839b92015-09-19 21:32:34 +0200278 }
279 builder.setParam(OAuth.OAUTH_RESPONSE_TYPE,
280 ResponseType.CODE.toString());
281 builder.setCode(authorizationCode);
Michael Hanl482f30d2015-09-25 12:39:46 +0200282 response = builder.buildBodyMessage();
Michael Hanlfb839b92015-09-19 21:32:34 +0200283
284 }else if (responseType.contains(ResponseType.TOKEN.toString())) {
Michael Hanl482f30d2015-09-25 12:39:46 +0200285 OAuthASResponse.OAuthTokenResponseBuilder builder = OAuthASResponse
286 .tokenResponse(HttpServletResponse.SC_OK);
Michael Hanlfb839b92015-09-19 21:32:34 +0200287 builder.setParam(OAuth.OAUTH_RESPONSE_TYPE,
288 ResponseType.TOKEN.toString());
Michael Hanl482f30d2015-09-25 12:39:46 +0200289 builder.location(redirectURI);
Michael Hanlfb839b92015-09-19 21:32:34 +0200290
291 String token = oauthIssuerImpl.accessToken();
Michael Hanl482f30d2015-09-25 12:39:46 +0200292 String refresh = oauthIssuerImpl.refreshToken();
293
294 this.handler.addToken(token, refresh, user.getId(),
295 oauthRequest.getClientId(),
296 StringUtils.toString(oauthRequest.getScopes(), " "),
Michael Hanlfb839b92015-09-19 21:32:34 +0200297 config.getLongTokenTTL());
298 builder.setAccessToken(token);
Michael Hanl482f30d2015-09-25 12:39:46 +0200299 builder.setRefreshToken(refresh);
300 builder.setExpiresIn(String.valueOf(config.getLongTokenTTL()));
Michael Hanlfb839b92015-09-19 21:32:34 +0200301
302 // skips authorization code type and returns id_token and access token directly
303 if (oauthRequest.getScopes().contains("openid")) {
304 try {
305 TokenContext new_context = this.controller
306 .createTokenContext(user, attr, null);
307 builder.setParam(new_context.getTokenType(),
308 new_context.getToken());
309 }catch (KustvaktException e) {
Michael Hanl482f30d2015-09-25 12:39:46 +0200310 throw KustvaktResponseHandler.throwit(e);
Michael Hanlfb839b92015-09-19 21:32:34 +0200311 }
312 }
Michael Hanl482f30d2015-09-25 12:39:46 +0200313 response = builder.buildBodyMessage();
Michael Hanlfb839b92015-09-19 21:32:34 +0200314 }else {
315 OAuthResponse res = OAuthASResponse
316 .errorResponse(HttpServletResponse.SC_BAD_REQUEST)
317 .setError(
318 OAuthError.CodeResponse.UNSUPPORTED_RESPONSE_TYPE)
319 .setErrorDescription("Unsupported Response type!\n")
320 .buildJSONMessage();
321 return Response.status(res.getResponseStatus())
322 .entity(res.getBody()).build();
323 }
Michael Hanl482f30d2015-09-25 12:39:46 +0200324 //
325 // String redirectURI = oauthRequest.getRedirectURI();
326 //
327 // // enables state parameter to disable cross-site scripting attacks
328 // final OAuthResponse response = builder.location(redirectURI)
329 // .buildQueryMessage();
330 // if (OAuthUtils.isEmpty(redirectURI)) {
331 // throw new WebApplicationException(
332 // Response.status(HttpServletResponse.SC_BAD_REQUEST)
333 // .entity("OAuth callback url needs to be provided by client!!!\n")
334 // .build());
335 // }
Michael Hanlfb839b92015-09-19 21:32:34 +0200336
337 return Response.status(response.getResponseStatus())
338 .location(new URI(response.getLocationUri())).build();
339 }catch (OAuthProblemException e) {
Michael Hanlfb839b92015-09-19 21:32:34 +0200340 final Response.ResponseBuilder responseBuilder = Response
341 .status(HttpServletResponse.SC_BAD_REQUEST);
342 String redirectUri = e.getRedirectUri();
343
344 if (OAuthUtils.isEmpty(redirectUri))
345 throw new WebApplicationException(responseBuilder
346 .entity("OAuth callback url needs to be provided by client!!!\n")
347 .build());
348
349 final OAuthResponse response = OAuthASResponse
350 .errorResponse(HttpServletResponse.SC_BAD_REQUEST).error(e)
351 .location(redirectUri).buildQueryMessage();
352 final URI location = new URI(response.getLocationUri());
353 return responseBuilder.location(location).build();
354 }catch (OAuthSystemException | URISyntaxException | KustvaktException e) {
355 e.printStackTrace();
356 }
357 return Response.noContent().build();
358 }
359
360 @POST
361 @Path("revoke")
362 public Response revokeToken(@Context HttpServletRequest request,
363 @Context SecurityContext context,
364 @HeaderParam(ContainerRequest.USER_AGENT) String agent,
365 @HeaderParam(ContainerRequest.HOST) String host)
366 throws OAuthSystemException, URISyntaxException {
367 TokenContext ctx = (TokenContext) context.getUserPrincipal();
368 try {
369
370 if (!this.handler.revokeToken(ctx.getToken())) {
371 OAuthResponse res = OAuthASResponse
372 .errorResponse(HttpServletResponse.SC_BAD_REQUEST)
373 .setError(OAuthError.TokenResponse.UNAUTHORIZED_CLIENT)
374 .setErrorDescription("Invalid access token!\n")
375 .buildJSONMessage();
376 return Response.status(res.getResponseStatus())
377 .entity(res.getBody()).build();
378 }
379
380 }catch (KustvaktException e) {
381 e.printStackTrace();
382 // fixme: do something
383 /**
384 * final Response.ResponseBuilder responseBuilder = Response
385 .status(HttpServletResponse.SC_FOUND);
386 String redirectUri = e.getRedirectUri();
387
388 final OAuthResponse response = OAuthASResponse
389 .errorResponse(HttpServletResponse.SC_FOUND).error(e)
390 .location(redirectUri).buildQueryMessage();
391 final URI location = new URI(response.getLocationUri());
392 return responseBuilder.location(location).build();
393 */
394 }
395
396 return Response.ok().build();
397 }
398
399 @POST
400 @Consumes("application/x-www-form-urlencoded")
401 @Produces("application/json")
402 @Path("token")
403 public Response requestToken(@Context HttpServletRequest request,
404 @HeaderParam(ContainerRequest.USER_AGENT) String agent,
405 @HeaderParam(ContainerRequest.HOST) String host,
406 MultivaluedMap form) throws OAuthSystemException {
407 boolean openid_valid = false;
408 User user = null;
409 OAuthTokenRequest oauthRequest;
410 OAuthASResponse.OAuthTokenResponseBuilder builder = OAuthASResponse
411 .tokenResponse(HttpServletResponse.SC_OK);
412
413 OAuthIssuer oauthIssuerImpl = new OAuthIssuerImpl(new MD5Generator());
414 ClientInfo info;
415 try {
416 oauthRequest = new OAuthTokenRequest(
417 new FormRequestWrapper(request, form));
418
419 if ((info = this.handler.getClient(oauthRequest.getClientId()))
420 == null) {
421 OAuthResponse res = OAuthASResponse
422 .errorResponse(HttpServletResponse.SC_BAD_REQUEST)
423 .setError(OAuthError.TokenResponse.INVALID_CLIENT)
424 .setErrorDescription("Invalid client id!\n")
425 .buildJSONMessage();
426 return Response.status(res.getResponseStatus())
427 .entity(res.getBody()).build();
428 }else if (!info.getClient_secret()
429 .equals(oauthRequest.getClientSecret())) {
430 OAuthResponse res = OAuthASResponse
431 .errorResponse(HttpServletResponse.SC_UNAUTHORIZED)
432 .setError(OAuthError.TokenResponse.UNAUTHORIZED_CLIENT)
433 .setErrorDescription("Invalid client secret!\n")
434 .buildJSONMessage();
435 return Response.status(res.getResponseStatus())
436 .entity(res.getBody()).build();
437 }
438
Michael Hanlf1e85e72016-01-21 16:55:45 +0100439 Map<String, String> attr = new HashMap<>();
Michael Hanlfb839b92015-09-19 21:32:34 +0200440 attr.put(Attributes.HOST, host);
441 attr.put(Attributes.USER_AGENT, agent);
442 attr.put(Attributes.SCOPES,
443 StringUtils.toString(oauthRequest.getScopes(), " "));
444
445 // support code (for external clients only) and password grant type
446 // password grant at this point is only allowed with trusted clients (korap frontend)
447 if (oauthRequest.getGrantType().equalsIgnoreCase(
448 GrantType.AUTHORIZATION_CODE.toString())) {
449 // validate auth code
450 AuthCodeInfo codeInfo;
451 try {
452 //can this be joined with the simple retrieval of access tokens?
453 // partially yes: auth code can be valid, even though no access token exists
454 // --> zero result set
455 codeInfo = this.handler
456 .getAuthorization(oauthRequest.getCode());
457 if (codeInfo == null) {
458 OAuthResponse res = OAuthASResponse.errorResponse(
459 HttpServletResponse.SC_UNAUTHORIZED).setError(
460 OAuthError.TokenResponse.INVALID_REQUEST)
461 .setErrorDescription(
462 "Invalid authorization code\n")
463 .buildJSONMessage();
464 return Response.status(res.getResponseStatus())
465 .entity(res.getBody()).build();
466 }else {
467 openid_valid = codeInfo.getScopes().contains("openid");
468 String accessToken = oauthIssuerImpl.accessToken();
Michael Hanl482f30d2015-09-25 12:39:46 +0200469 String refreshToken = oauthIssuerImpl.refreshToken();
Michael Hanlfb839b92015-09-19 21:32:34 +0200470 // auth code posesses the user reference. native apps access_tokens are directly associated with the user
471 this.handler
472 .addToken(oauthRequest.getCode(), accessToken,
Michael Hanl482f30d2015-09-25 12:39:46 +0200473 refreshToken, config.getTokenTTL());
Michael Hanlfb839b92015-09-19 21:32:34 +0200474
475 builder.setTokenType(TokenType.BEARER.toString());
476 builder.setExpiresIn(
477 String.valueOf(config.getLongTokenTTL()));
478 builder.setAccessToken(accessToken);
Michael Hanl482f30d2015-09-25 12:39:46 +0200479 builder.setRefreshToken(refreshToken);
Michael Hanlfb839b92015-09-19 21:32:34 +0200480 }
481 }catch (KustvaktException e) {
Michael Hanl482f30d2015-09-25 12:39:46 +0200482 throw KustvaktResponseHandler.throwit(e);
Michael Hanlfb839b92015-09-19 21:32:34 +0200483 }
484 // todo: errors for invalid scopes or different scopes then during authorization request?
485 //todo ??
486 attr.put(Attributes.SCOPES, codeInfo.getScopes());
487
488 }else if (oauthRequest.getGrantType()
489 .equalsIgnoreCase(GrantType.PASSWORD.toString())) {
490 //fixme: via https; as basic auth header and only if client is native!
491 if (!info.isConfidential()) {
492 OAuthResponse res = OAuthASResponse
493 .errorResponse(HttpServletResponse.SC_BAD_REQUEST)
494 .setError(
495 OAuthError.TokenResponse.UNAUTHORIZED_CLIENT)
496 .setErrorDescription(
497 "Grant type not supported for client!\n")
498 .buildJSONMessage();
499 return Response.status(res.getResponseStatus())
500 .entity(res.getBody()).build();
501 }
502
503 openid_valid = true;
504 try {
505 user = controller
506 .authenticate(0, oauthRequest.getUsername(),
507 oauthRequest.getPassword(), attr);
508 }catch (KustvaktException e) {
Michael Hanl482f30d2015-09-25 12:39:46 +0200509 throw KustvaktResponseHandler.throwit(e);
Michael Hanlfb839b92015-09-19 21:32:34 +0200510 }
511
512 try {
513 String accessToken = this.handler
514 .getToken(oauthRequest.getClientId(), user.getId());
515 if (accessToken == null) {
Michael Hanl482f30d2015-09-25 12:39:46 +0200516 String refresh = oauthIssuerImpl.refreshToken();
Michael Hanlfb839b92015-09-19 21:32:34 +0200517 accessToken = oauthIssuerImpl.accessToken();
Michael Hanl482f30d2015-09-25 12:39:46 +0200518 this.handler
519 .addToken(accessToken, refresh, user.getId(),
520 oauthRequest.getClientId(), StringUtils
521 .toString(oauthRequest
522 .getScopes(), " "),
523 config.getLongTokenTTL());
524 builder.setRefreshToken(refresh);
Michael Hanlfb839b92015-09-19 21:32:34 +0200525 }
526 builder.setTokenType(TokenType.BEARER.toString());
527 builder.setExpiresIn(
528 String.valueOf(config.getLongTokenTTL()));
529 builder.setAccessToken(accessToken);
530
531 }catch (KustvaktException e) {
Michael Hanl482f30d2015-09-25 12:39:46 +0200532 throw KustvaktResponseHandler.throwit(e);
Michael Hanlfb839b92015-09-19 21:32:34 +0200533 }
534 }
535
536 if (openid_valid && oauthRequest.getScopes()
537 .contains(Scopes.Scope.openid.toString())) {
538 try {
539 if (user == null)
540 user = controller
541 .authenticate(0, oauthRequest.getUsername(),
542 oauthRequest.getPassword(), attr);
543 controller.getUserDetails(user);
544 attr.put(Attributes.CLIENT_SECRET,
545 oauthRequest.getClientSecret());
546 TokenContext c = controller.createTokenContext(user, attr,
547 Attributes.OPENID_AUTHENTICATION);
548 builder.setParam(c.getTokenType(), c.getToken());
549 }catch (KustvaktException e) {
Michael Hanl482f30d2015-09-25 12:39:46 +0200550 throw KustvaktResponseHandler.throwit(e);
Michael Hanlfb839b92015-09-19 21:32:34 +0200551 }
552 }
553
554 OAuthResponse r = builder.buildJSONMessage();
555 return Response.status(r.getResponseStatus()).entity(r.getBody())
556 .build();
557 }catch (OAuthProblemException ex) {
558 OAuthResponse r = OAuthResponse.errorResponse(401).error(ex)
559 .buildJSONMessage();
560 return Response.status(r.getResponseStatus()).entity(r.getBody())
561 .build();
562 }catch (OAuthSystemException e) {
563 e.printStackTrace();
564 // todo: throw error
565 }
566 return Response.noContent().build();
567 }
568
569}