org.cloudfoundry.identity.uaa.oauth.TokenRevocationEndpoint.java Source code

Java tutorial

Introduction

Here is the source code for org.cloudfoundry.identity.uaa.oauth.TokenRevocationEndpoint.java

Source

/*
 * *****************************************************************************
 *      Cloud Foundry
 *      Copyright (c) [2009-2015] Pivotal Software, Inc. All Rights Reserved.
 *      This product is licensed to you under the Apache License, Version 2.0 (the "License").
 *      You may not use this product except in compliance with the License.
 *
 *      This product includes a number of subcomponents with
 *      separate copyright notices and license terms. Your use of these
 *      subcomponents is subject to the terms and conditions of the
 *      subcomponent's license, as noted in the LICENSE file.
 * *****************************************************************************
 */

package org.cloudfoundry.identity.uaa.oauth;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal;
import org.cloudfoundry.identity.uaa.oauth.client.ClientConstants;
import org.cloudfoundry.identity.uaa.oauth.token.RevocableToken;
import org.cloudfoundry.identity.uaa.oauth.token.RevocableTokenProvisioning;
import org.cloudfoundry.identity.uaa.scim.ScimUser;
import org.cloudfoundry.identity.uaa.scim.ScimUserProvisioning;
import org.cloudfoundry.identity.uaa.scim.exception.ScimResourceNotFoundException;
import org.cloudfoundry.identity.uaa.zone.MultitenantJdbcClientDetailsService;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.common.util.RandomValueStringGenerator;
import org.springframework.security.oauth2.provider.NoSuchClientException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.expression.OAuth2ExpressionUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

import static org.springframework.http.HttpStatus.OK;
import static org.springframework.web.bind.annotation.RequestMethod.DELETE;
import static org.springframework.web.bind.annotation.RequestMethod.GET;

@Controller
public class TokenRevocationEndpoint {

    protected final Log logger = LogFactory.getLog(getClass());
    private WebResponseExceptionTranslator exceptionTranslator = new DefaultWebResponseExceptionTranslator();
    private final ScimUserProvisioning userProvisioning;
    private final MultitenantJdbcClientDetailsService clientDetailsService;
    private final RandomValueStringGenerator generator = new RandomValueStringGenerator(8);
    private final RevocableTokenProvisioning tokenProvisioning;

    public TokenRevocationEndpoint(MultitenantJdbcClientDetailsService clientDetailsService,
            ScimUserProvisioning userProvisioning, RevocableTokenProvisioning tokenProvisioning) {
        this.clientDetailsService = clientDetailsService;
        this.userProvisioning = userProvisioning;
        this.tokenProvisioning = tokenProvisioning;
    }

    @RequestMapping("/oauth/token/revoke/user/{userId}")
    public ResponseEntity<Void> revokeTokensForUser(@PathVariable String userId) {
        logger.debug("Revoking tokens for user: " + userId);
        ScimUser user = userProvisioning.retrieve(userId);
        user.setSalt(generator.generate());
        userProvisioning.update(userId, user);
        logger.debug("Tokens revoked for user: " + userId);
        return new ResponseEntity<>(OK);
    }

    @RequestMapping("/oauth/token/revoke/client/{clientId}")
    public ResponseEntity<Void> revokeTokensForClient(@PathVariable String clientId) {
        logger.debug("Revoking tokens for client: " + clientId);
        BaseClientDetails client = (BaseClientDetails) clientDetailsService.loadClientByClientId(clientId);
        client.addAdditionalInformation(ClientConstants.TOKEN_SALT, generator.generate());
        clientDetailsService.updateClientDetails(client);
        logger.debug("Tokens revoked for client: " + clientId);
        return new ResponseEntity<>(OK);
    }

    @RequestMapping(value = "/oauth/token/revoke/{tokenId}", method = DELETE)
    public ResponseEntity<Void> revokeTokenById(@PathVariable String tokenId) {
        logger.debug("Revoking token with ID:" + tokenId);
        tokenProvisioning.delete(tokenId, -1);
        logger.debug("Revoked token with ID: " + tokenId);
        return new ResponseEntity<>(OK);
    }

    @RequestMapping(value = "/oauth/token/list", method = GET)
    public ResponseEntity<List<RevocableToken>> listUserTokens(OAuth2Authentication authentication) {
        UaaPrincipal principal = (UaaPrincipal) authentication.getUserAuthentication().getPrincipal();
        String userId = principal.getId();
        String clientId = authentication.getOAuth2Request().getClientId();
        logger.debug("Listing revocable tokens access token userId:" + userId + " clientId:" + clientId);
        List<RevocableToken> result = tokenProvisioning.getUserTokens(userId, clientId);
        removeTokenValues(result);
        return new ResponseEntity<>(result, OK);
    }

    protected void removeTokenValues(List<RevocableToken> result) {
        result.stream().forEach(t -> t.setValue(null));
    }

    @RequestMapping(value = "/oauth/token/list/user/{userId}", method = GET)
    public ResponseEntity<List<RevocableToken>> listUserTokens(@PathVariable String userId,
            OAuth2Authentication authentication) {
        if (OAuth2ExpressionUtils.hasAnyScope(authentication, new String[] { "tokens.list", "uaa.admin" })) {
            logger.debug("Listing revocable tokens for user:" + userId);
            List<RevocableToken> result = tokenProvisioning.getUserTokens(userId);
            removeTokenValues(result);
            return new ResponseEntity<>(result, OK);
        } else {
            return listUserTokens(authentication);
        }
    }

    @RequestMapping(value = "/oauth/token/list/client/{clientId}", method = GET)
    public ResponseEntity<List<RevocableToken>> listClientTokens(@PathVariable String clientId,
            OAuth2Authentication authentication) {
        if (OAuth2ExpressionUtils.hasAnyScope(authentication, new String[] { "tokens.list", "uaa.admin" })) {
            logger.debug("Listing revocable tokens for client:" + clientId);
            List<RevocableToken> result = tokenProvisioning.getClientTokens(clientId);
            removeTokenValues(result);
            return new ResponseEntity<>(result, OK);
        } else {
            return listUserTokens(authentication);
        }
    }

    @ExceptionHandler({ ScimResourceNotFoundException.class, NoSuchClientException.class,
            EmptyResultDataAccessException.class })
    public ResponseEntity<OAuth2Exception> handleException(Exception e) throws Exception {
        logger.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
        InvalidTokenException e404 = new InvalidTokenException("Resource not found") {
            @Override
            public int getHttpErrorCode() {
                return 404;
            }
        };
        return exceptionTranslator.translate(e404);
    }
}