Package org.mitre.oauth2.introspectingfilter

Source Code of org.mitre.oauth2.introspectingfilter.IntrospectingTokenService$TokenCacheObject

/*******************************************************************************
* Copyright 2014 The MITRE Corporation
*   and the MIT Kerberos and Internet Trust Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.mitre.oauth2.introspectingfilter;

import static org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod.SECRET_BASIC;

import java.io.IOException;
import java.net.URI;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.SystemDefaultHttpClient;
import org.mitre.oauth2.introspectingfilter.service.IntrospectionAuthorityGranter;
import org.mitre.oauth2.introspectingfilter.service.IntrospectionConfigurationService;
import org.mitre.oauth2.introspectingfilter.service.impl.SimpleIntrospectionAuthorityGranter;
import org.mitre.oauth2.model.RegisteredClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.nimbusds.jose.util.Base64;

/**
* This ResourceServerTokenServices implementation introspects incoming tokens at a
* server's introspection endpoint URL and passes an Authentication object along
* based on the response from the introspection endpoint.
* @author jricher
*
*/
public class IntrospectingTokenService implements ResourceServerTokenServices {

  private IntrospectionConfigurationService introspectionConfigurationService;
  private IntrospectionAuthorityGranter introspectionAuthorityGranter = new SimpleIntrospectionAuthorityGranter();

  private HttpClient httpClient = new SystemDefaultHttpClient();
  private HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);

  // Inner class to store in the hash map
  private class TokenCacheObject {
    OAuth2AccessToken token;
    OAuth2Authentication auth;

    private TokenCacheObject(OAuth2AccessToken token, OAuth2Authentication auth) {
      this.token = token;
      this.auth = auth;
    }
  }

  private Map<String, TokenCacheObject> authCache = new HashMap<String, TokenCacheObject>();
  private static Logger logger = LoggerFactory.getLogger(IntrospectingTokenService.class);

  /**
   * @return the introspectionConfigurationService
   */
  public IntrospectionConfigurationService getIntrospectionConfigurationService() {
    return introspectionConfigurationService;
  }

  /**
   * @param introspectionConfigurationService the introspectionConfigurationService to set
   */
  public void setIntrospectionConfigurationService(IntrospectionConfigurationService introspectionUrlProvider) {
    this.introspectionConfigurationService = introspectionUrlProvider;
  }

  /**
   * @param introspectionAuthorityGranter the introspectionAuthorityGranter to set
   */
  public void setIntrospectionAuthorityGranter(IntrospectionAuthorityGranter introspectionAuthorityGranter) {
    this.introspectionAuthorityGranter = introspectionAuthorityGranter;
  }

  /**
   * @return the introspectionAuthorityGranter
   */
  public IntrospectionAuthorityGranter getIntrospectionAuthorityGranter() {
    return introspectionAuthorityGranter;
  }

  // Check if there is a token and authentication in the cache
  // and check if it is not expired.
  private TokenCacheObject checkCache(String key) {
    if (authCache.containsKey(key)) {
      TokenCacheObject tco = authCache.get(key);
      if (tco.token.getExpiration().after(new Date())) {
        return tco;
      } else {
        // if the token is expired, don't keep things around.
        authCache.remove(key);
      }
    }
    return null;
  }

  private OAuth2Request createStoredRequest(final JsonObject token) {
    String clientId = token.get("client_id").getAsString();
    Set<String> scopes = new HashSet<String>();
    if (token.has("scope")) {
      scopes.addAll(OAuth2Utils.parseParameterList(token.get("scope").getAsString()));
    }
    Map<String, String> parameters = new HashMap<String, String>();
    parameters.put("client_id", clientId);
    parameters.put("scope", OAuth2Utils.formatParameterList(scopes));
    OAuth2Request storedRequest = new OAuth2Request(parameters, clientId, null, true, scopes, null, null, null, null);
    return storedRequest;
  }

  private Authentication createAuthentication(JsonObject token) {
    return new PreAuthenticatedAuthenticationToken(token.get("sub").getAsString(), token, introspectionAuthorityGranter.getAuthorities(token));
  }

  private OAuth2AccessToken createAccessToken(final JsonObject token, final String tokenString) {
    OAuth2AccessToken accessToken = new OAuth2AccessTokenImpl(token, tokenString);
    return accessToken;
  }

  // Validate a token string against the introspection endpoint,
  // then parse it and store it in the local cache. Return true on
  // sucess, false otherwise.
  private boolean parseToken(String accessToken) {

    // find out which URL to ask
    String introspectionUrl;
    RegisteredClient client;
    try {
      introspectionUrl = introspectionConfigurationService.getIntrospectionUrl(accessToken);
      client = introspectionConfigurationService.getClientConfiguration(accessToken);
    } catch (IllegalArgumentException e) {
      logger.error("Unable to load introspection URL or client configuration", e);
      return false;
    }
    // Use the SpringFramework RestTemplate to send the request to the
    // endpoint
    String validatedToken = null;

    RestTemplate restTemplate;
    MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();

    final String clientId = client.getClientId();
    final String clientSecret = client.getClientSecret();

    if (SECRET_BASIC.equals(client.getTokenEndpointAuthMethod())){
      // use BASIC auth if configured to do so
      restTemplate = new RestTemplate(factory) {

        @Override
        protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
          ClientHttpRequest httpRequest = super.createRequest(url, method);
          httpRequest.getHeaders().add("Authorization",
              String.format("Basic %s", Base64.encode(String.format("%s:%s", clientId, clientSecret)) ));
          return httpRequest;
        }
      };
    } else //Alternatively use form based auth
      restTemplate = new RestTemplate(factory);

      form.add("client_id", clientId);
      form.add("client_secret", clientSecret);
    }

    form.add("token", accessToken);

    try {
      validatedToken = restTemplate.postForObject(introspectionUrl, form, String.class);
    } catch (RestClientException rce) {
      logger.error("validateToken", rce);
    }
    if (validatedToken != null) {
      // parse the json
      JsonElement jsonRoot = new JsonParser().parse(validatedToken);
      if (!jsonRoot.isJsonObject()) {
        return false; // didn't get a proper JSON object
      }

      JsonObject tokenResponse = jsonRoot.getAsJsonObject();

      if (tokenResponse.get("error") != null) {
        // report an error?
        logger.error("Got an error back: " + tokenResponse.get("error") + ", " + tokenResponse.get("error_description"));
        return false;
      }

      if (!tokenResponse.get("active").getAsBoolean()) {
        // non-valid token
        logger.info("Server returned non-active token");
        return false;
      }
      // create an OAuth2Authentication
      OAuth2Authentication auth = new OAuth2Authentication(createStoredRequest(tokenResponse), createAuthentication(tokenResponse));
      // create an OAuth2AccessToken
      OAuth2AccessToken token = createAccessToken(tokenResponse, accessToken);

      if (token.getExpiration().after(new Date())) {
        // Store them in the cache
        authCache.put(accessToken, new TokenCacheObject(token, auth));

        return true;
      }
    }

    // If we never put a token and an authentication in the cache...
    return false;
  }

  @Override
  public OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException {
    // First check if the in memory cache has an Authentication object, and
    // that it is still valid
    // If Valid, return it
    TokenCacheObject cacheAuth = checkCache(accessToken);
    if (cacheAuth != null) {
      return cacheAuth.auth;
    } else {
      if (parseToken(accessToken)) {
        cacheAuth = authCache.get(accessToken);
        if (cacheAuth != null && (cacheAuth.token.getExpiration().after(new Date()))) {
          return cacheAuth.auth;
        } else {
          return null;
        }
      } else {
        return null;
      }
    }
  }

  @Override
  public OAuth2AccessToken readAccessToken(String accessToken) {
    // First check if the in memory cache has a Token object, and that it is
    // still valid
    // If Valid, return it
    TokenCacheObject cacheAuth = checkCache(accessToken);
    if (cacheAuth != null) {
      return cacheAuth.token;
    } else {
      if (parseToken(accessToken)) {
        cacheAuth = authCache.get(accessToken);
        if (cacheAuth != null && (cacheAuth.token.getExpiration().after(new Date()))) {
          return cacheAuth.token;
        } else {
          return null;
        }
      } else {
        return null;
      }
    }
  }

}
TOP

Related Classes of org.mitre.oauth2.introspectingfilter.IntrospectingTokenService$TokenCacheObject

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.