org.cloudfoundry.identity.uaa.oauth.token.TokenKeyEndpoint.java Source code

Java tutorial

Introduction

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

Source

/*******************************************************************************
 *     Cloud Foundry 
 *     Copyright (c) [2009-2014] 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.token;

import java.lang.reflect.Field;
import java.math.BigInteger;
import java.security.Principal;
import java.security.interfaces.RSAPublicKey;
import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.crypto.codec.Base64;
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
import org.springframework.security.jwt.crypto.sign.SignatureVerifier;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * OAuth2 token services that produces JWT encoded token values.
 * 
 * @author Dave Syer
 * @author Luke Taylor
 * @author Joel D'sa
 */
@Controller
public class TokenKeyEndpoint implements InitializingBean {

    protected final Log logger = LogFactory.getLog(getClass());

    private SignerProvider signerProvider;

    /**
     * @param signerProvider the signerProvider to set
     */
    public void setSignerProvider(SignerProvider signerProvider) {
        this.signerProvider = signerProvider;
    }

    /**
     * Get the verification key for the token signatures. The principal has to
     * be provided only if the key is secret
     * (shared not public).
     * 
     * @param principal the currently authenticated user if there is one
     * @return the key used to verify tokens
     */
    @RequestMapping(value = "/token_key", method = RequestMethod.GET)
    @ResponseBody
    public Map<String, String> getKey(Principal principal) {
        if ((principal == null || principal instanceof AnonymousAuthenticationToken)
                && !signerProvider.isPublic()) {
            throw new AccessDeniedException("You need to authenticate to see a shared key");
        }
        Map<String, String> result = new LinkedHashMap<String, String>();
        result.put("alg", signerProvider.getSigner().algorithm());
        result.put("value", signerProvider.getVerifierKey());
        //new values per OpenID and JWK spec
        result.put("kty", signerProvider.getType());
        result.put("use", "sig");
        if (signerProvider.isPublic() && "RSA".equals(signerProvider.getType())) {
            SignatureVerifier verifier = signerProvider.getVerifier();
            if (verifier != null && verifier instanceof RsaVerifier) {
                RSAPublicKey rsaKey = extractRsaPublicKey((RsaVerifier) verifier);
                if (rsaKey != null) {
                    String n = new String(Base64.encode(rsaKey.getModulus().toByteArray()));
                    String e = new String(Base64.encode(rsaKey.getPublicExponent().toByteArray()));
                    result.put("n", n);
                    result.put("e", e);
                }
            }
        }
        return result;
    }

    private RSAPublicKey extractRsaPublicKey(RsaVerifier verifier) {
        try {
            Field f = verifier.getClass().getDeclaredField("key");
            if (f != null) {
                f.setAccessible(true);
                if (f.get(verifier) instanceof RSAPublicKey) {
                    return (RSAPublicKey) f.get(verifier);
                }
            }
        } catch (NoSuchFieldException e) {

        } catch (IllegalAccessException e) {

        } catch (ClassCastException x) {

        }
        return null;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Assert.state(this.signerProvider != null, "A SignerProvider must be provided");
    }
}