Search in sources :

Example 1 with TokenEntry

use of org.codice.ddf.security.token.storage.api.TokenInformation.TokenEntry in project ddf by codice.

the class OAuthPlugin method findExistingTokens.

/**
 * Looks through the user's tokens to see if there are tokens from a different source connected to
 * the same OAuth provider. The discovery URLs need to match. If a match is found an authorize
 * source exception will be thrown so the user can authorize to query the new source instead of
 * logging in.
 */
private void findExistingTokens(OAuthFederatedSource oauthSource, String sessionId, OIDCProviderMetadata metadata) throws StopProcessingException {
    TokenInformation tokenInformation = tokenStorage.read(sessionId);
    if (tokenInformation == null || !tokenInformation.getDiscoveryUrls().contains(oauthSource.getOauthDiscoveryUrl())) {
        return;
    }
    // Verify that an unexpired token exists
    List<TokenInformation.TokenEntry> matchingTokenEntries = tokenInformation.getTokenEntries().entrySet().stream().filter(entry -> !entry.getKey().equals(oauthSource.getId())).filter(entry -> entry.getValue().getDiscoveryUrl().equals(oauthSource.getOauthDiscoveryUrl())).map(Map.Entry::getValue).collect(Collectors.toList());
    TokenInformation.TokenEntry tokenEntry = matchingTokenEntries.stream().filter(entry -> entry.getAccessToken() != null).filter(entry -> !isExpired(entry.getAccessToken())).findAny().orElse(null);
    if (tokenEntry == null) {
        // does one with a valid refresh token exist
        tokenEntry = matchingTokenEntries.stream().filter(entry -> entry.getRefreshToken() != null).filter(entry -> !isExpired(entry.getRefreshToken())).findAny().orElse(null);
        if (tokenEntry == null) {
            return;
        }
        refreshTokens(tokenEntry.getRefreshToken(), oauthSource, sessionId, metadata);
    }
    LOGGER.debug("Unable to process query. The user needs to authorize to query the {} source.", oauthSource.getId());
    Map<String, String> parameters = new HashMap<>();
    parameters.put(SOURCE_ID, oauthSource.getId());
    parameters.put(DISCOVERY_URL, oauthSource.getOauthDiscoveryUrl());
    throw new OAuthPluginException(oauthSource.getId(), buildUrl(AUTHORIZE_SOURCE_ENDPOINT, parameters), AUTHORIZE_SOURCE_ENDPOINT, parameters, AUTH_SOURCE);
}
Also used : STATE(org.codice.ddf.security.token.storage.api.TokenStorage.STATE) Arrays(java.util.Arrays) URL(java.net.URL) URISyntaxException(java.net.URISyntaxException) RefreshTokenGrant(org.apache.cxf.rs.security.oauth2.grants.refresh.RefreshTokenGrant) LoggerFactory(org.slf4j.LoggerFactory) DefaultResourceRetriever(com.nimbusds.jose.util.DefaultResourceRetriever) Session(org.apache.shiro.session.Session) ClientAccessToken(org.apache.cxf.rs.security.oauth2.common.ClientAccessToken) GsonBuilder(com.google.gson.GsonBuilder) NO_AUTH(ddf.catalog.plugin.OAuthPluginException.ErrorType.NO_AUTH) OAuthClientUtils(org.apache.cxf.rs.security.oauth2.client.OAuthClientUtils) OAuthFederatedSource(ddf.catalog.source.OAuthFederatedSource) EXPIRES_AT(org.codice.ddf.security.token.storage.api.TokenStorage.EXPIRES_AT) Gson(com.google.gson.Gson) OidcTokenValidator(org.codice.ddf.security.oidc.validator.OidcTokenValidator) Map(java.util.Map) Bundle(org.osgi.framework.Bundle) TokenInformation(org.codice.ddf.security.token.storage.api.TokenInformation) ServiceReference(org.osgi.framework.ServiceReference) Consumer(org.apache.cxf.rs.security.oauth2.client.Consumer) AccessToken(com.nimbusds.oauth2.sdk.token.AccessToken) OAuthPluginException(ddf.catalog.plugin.OAuthPluginException) InvalidSyntaxException(org.osgi.framework.InvalidSyntaxException) URIBuilder(org.apache.http.client.utils.URIBuilder) Collection(java.util.Collection) UUID(java.util.UUID) Instant(java.time.Instant) Collectors(java.util.stream.Collectors) BundleContext(org.osgi.framework.BundleContext) Base64(java.util.Base64) List(java.util.List) OAuthServiceException(org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException) HashMap(java.util.HashMap) TokenEntry(org.codice.ddf.security.token.storage.api.TokenInformation.TokenEntry) SECRET(org.codice.ddf.security.token.storage.api.TokenStorage.SECRET) SOURCE_ID(org.codice.ddf.security.token.storage.api.TokenStorage.SOURCE_ID) Source(ddf.catalog.source.Source) DISCOVERY_URL(org.codice.ddf.security.token.storage.api.TokenStorage.DISCOVERY_URL) QueryRequest(ddf.catalog.operation.QueryRequest) AUTH_SOURCE(ddf.catalog.plugin.OAuthPluginException.ErrorType.AUTH_SOURCE) ParseException(com.nimbusds.oauth2.sdk.ParseException) CLIENT_ID(org.codice.ddf.security.token.storage.api.TokenStorage.CLIENT_ID) GsonTypeAdapters(org.codice.gsonsupport.GsonTypeAdapters) PreFederatedQueryPlugin(ddf.catalog.plugin.PreFederatedQueryPlugin) Logger(org.slf4j.Logger) SystemBaseUrl(org.codice.ddf.configuration.SystemBaseUrl) OIDCProviderMetadata(com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata) MalformedURLException(java.net.MalformedURLException) WebClient(org.apache.cxf.jaxrs.client.WebClient) BearerAccessToken(com.nimbusds.oauth2.sdk.token.BearerAccessToken) Scope(com.nimbusds.oauth2.sdk.Scope) StopProcessingException(ddf.catalog.plugin.StopProcessingException) Subject(ddf.security.Subject) IOException(java.io.IOException) SECURITY_SUBJECT(ddf.security.SecurityConstants.SECURITY_SUBJECT) OidcValidationException(org.codice.ddf.security.oidc.validator.OidcValidationException) MAP_STRING_TO_OBJECT_TYPE(org.codice.gsonsupport.GsonTypeAdapters.MAP_STRING_TO_OBJECT_TYPE) ResourceRetriever(com.nimbusds.jose.util.ResourceRetriever) SC_OK(org.apache.http.HttpStatus.SC_OK) ChronoUnit(java.time.temporal.ChronoUnit) TokenStorage(org.codice.ddf.security.token.storage.api.TokenStorage) VisibleForTesting(com.google.common.annotations.VisibleForTesting) AccessTokenGrant(org.apache.cxf.rs.security.oauth2.common.AccessTokenGrant) TypelessAccessToken(com.nimbusds.oauth2.sdk.token.TypelessAccessToken) FrameworkUtil(org.osgi.framework.FrameworkUtil) TokenEntry(org.codice.ddf.security.token.storage.api.TokenInformation.TokenEntry) OAuthPluginException(ddf.catalog.plugin.OAuthPluginException) TokenEntry(org.codice.ddf.security.token.storage.api.TokenInformation.TokenEntry) HashMap(java.util.HashMap) TokenInformation(org.codice.ddf.security.token.storage.api.TokenInformation) Map(java.util.Map) HashMap(java.util.HashMap)

Example 2 with TokenEntry

use of org.codice.ddf.security.token.storage.api.TokenInformation.TokenEntry in project ddf by codice.

the class OAuthPlugin method process.

/**
 * Verifies that a source configured to use OAuth has a valid access token to process and that the
 * user has authorized the use of their data against this source.
 *
 * @param source source being queried
 * @param input query request
 * @throws OAuthPluginException if the user's access token is not available or if the source is
 *     not authorized
 * @throws StopProcessingException for errors not related to OAuth
 */
@Override
public QueryRequest process(Source source, QueryRequest input) throws StopProcessingException {
    OAuthFederatedSource oauthSource = getSource(source);
    if (oauthSource == null) {
        return input;
    }
    Object securityAssertion = input.getProperties().get(SECURITY_SUBJECT);
    if (!(securityAssertion instanceof Subject)) {
        LOGGER.warn("The user's subject is not available.");
        throw new StopProcessingException("The user's subject is not available.");
    }
    Subject subject = (Subject) securityAssertion;
    Session session = subject.getSession(false);
    if (session == null) {
        LOGGER.warn("The user's session is not available.");
        throw new StopProcessingException("The user's session is not available.");
    }
    String sessionId = (String) session.getId();
    if (sessionId == null) {
        LOGGER.warn("The user's session ID is not available.");
        throw new StopProcessingException("The user's session ID is not available.");
    }
    OIDCProviderMetadata metadata;
    try {
        metadata = OIDCProviderMetadata.parse(resourceRetriever.retrieveResource(new URL(oauthSource.getOauthDiscoveryUrl())).getContent());
    } catch (OAuthServiceException | IOException | ParseException e) {
        LOGGER.error("Unable to retrieve OAuth provider's metadata for the {} source.", oauthSource.getId());
        throw new StopProcessingException("Unable to retrieve OAuth provider's metadata.");
    }
    TokenEntry tokenEntry = tokenStorage.read(sessionId, oauthSource.getId());
    if (tokenEntry == null) {
        // See if the user already logged in to the OAuth provider for a different source
        findExistingTokens(oauthSource, sessionId, metadata);
        throw createNoAuthException(oauthSource, sessionId, metadata, "the user's tokens were not found.");
    }
    // an outdated token)
    if (!oauthSource.getOauthDiscoveryUrl().equals(tokenEntry.getDiscoveryUrl())) {
        // the discoveryUrl is different from the one stored - the user must login
        tokenStorage.delete(sessionId, oauthSource.getId());
        findExistingTokens(oauthSource, sessionId, metadata);
        throw createNoAuthException(oauthSource, sessionId, metadata, "the oauth provider information has been changed and is different from the one stored.");
    }
    verifyAccessToken(oauthSource, sessionId, tokenEntry, metadata);
    return input;
}
Also used : OAuthFederatedSource(ddf.catalog.source.OAuthFederatedSource) OAuthServiceException(org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException) StopProcessingException(ddf.catalog.plugin.StopProcessingException) IOException(java.io.IOException) Subject(ddf.security.Subject) URL(java.net.URL) DISCOVERY_URL(org.codice.ddf.security.token.storage.api.TokenStorage.DISCOVERY_URL) TokenEntry(org.codice.ddf.security.token.storage.api.TokenInformation.TokenEntry) OIDCProviderMetadata(com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata) ParseException(com.nimbusds.oauth2.sdk.ParseException) Session(org.apache.shiro.session.Session)

Example 3 with TokenEntry

use of org.codice.ddf.security.token.storage.api.TokenInformation.TokenEntry in project ddf by codice.

the class FileSystemTokenStorage method delete.

/**
 * Removes tokens associated with the given ID for the specified source
 *
 * @param id the ID associated with the tokens
 * @param sourceId the ID for the source the tokens are going to be used against
 * @return an HTTP status code
 */
@Override
public int delete(String id, String sourceId) {
    LOGGER.trace("Delete: Deleting a Token Storage entry.");
    TokenInformation tokenInformation = read(id);
    if (tokenInformation == null) {
        return SC_OK;
    }
    TokenEntry tokenEntry = tokenInformation.getTokenEntries().get(sourceId);
    if (tokenEntry == null) {
        return SC_OK;
    }
    Path contentItemPath = Paths.get(baseDirectory.toAbsolutePath().toString(), tokenInformation.getId());
    if (tokenInformation.getTokenEntries().size() == 1) {
        // delete file
        try {
            Files.delete(contentItemPath);
            return SC_OK;
        } catch (IOException e) {
            LOGGER.debug("Error deleting token file.", e);
            return SC_INTERNAL_SERVER_ERROR;
        }
    }
    String json = TokenInformationUtil.removeTokens(tokenInformation.getTokenJson(), sourceId);
    return writeToFile(contentItemPath, json);
}
Also used : Path(java.nio.file.Path) TokenEntry(org.codice.ddf.security.token.storage.api.TokenInformation.TokenEntry) TokenInformation(org.codice.ddf.security.token.storage.api.TokenInformation) IOException(java.io.IOException)

Example 4 with TokenEntry

use of org.codice.ddf.security.token.storage.api.TokenInformation.TokenEntry in project ddf by codice.

the class OAuthSecurityImpl method setUserTokenOnClient.

/**
 * Gets the user's access token from the token storage to set it to the OAUTH header. Used when a
 * source is configured to use Authentication Code flow/grant.
 *
 * @param client Non-null client to set the access token on.
 * @param subject subject used to get the session ID
 * @param sourceId the id of the source using OAuth needed to get the correct tokens
 */
@Override
public void setUserTokenOnClient(Client client, Subject subject, String sourceId) {
    if (client == null || subject == null || Strings.isBlank(sourceId)) {
        return;
    }
    Session session = subject.getSession(false);
    if (session == null) {
        LOGGER.warn("The user's session is not available.");
        return;
    }
    String sessionId = (String) session.getId();
    if (sessionId == null) {
        LOGGER.warn("The user's session ID is not available.");
        return;
    }
    TokenInformation.TokenEntry tokenEntry = tokenStorage.read(sessionId, sourceId);
    if (tokenEntry == null) {
        return;
    }
    LOGGER.debug(ADDING_TOKEN);
    client.header(OAUTH, BEARER + tokenEntry.getAccessToken());
}
Also used : TokenEntry(org.codice.ddf.security.token.storage.api.TokenInformation.TokenEntry) TokenInformation(org.codice.ddf.security.token.storage.api.TokenInformation) Session(org.apache.shiro.session.Session)

Example 5 with TokenEntry

use of org.codice.ddf.security.token.storage.api.TokenInformation.TokenEntry in project ddf by codice.

the class OAuthSecurityImpl method getValidToken.

/**
 * Attempts to get an unexpired access token from the token storage or by making a request to the
 * OAuth provider.
 *
 * @param id The ID used when retrieving tokens from the token storage
 * @param sourceId The ID of the source using OAuth needed to get the correct tokens
 * @param clientId The client ID registered with the OAuth provider
 * @param clientSecret The client secret registered with the OAuth provider
 * @param discoveryUrl The discovery URL of the OAuth provider
 * @param grantType The grant type used if a request is sent to get a new token
 * @param queryParameters Parameters used if a request is sent to get a new token
 * @return an access token or null if all means of getting one fail
 */
private String getValidToken(String id, String sourceId, String clientId, String clientSecret, String discoveryUrl, String grantType, Map<String, String> queryParameters) {
    TokenEntry tokenEntry = tokenStorage.read(id, sourceId);
    if (tokenEntry != null && discoveryUrl.equalsIgnoreCase(tokenEntry.getDiscoveryUrl()) && !isExpired(tokenEntry.getAccessToken())) {
        return tokenEntry.getAccessToken();
    }
    OIDCProviderMetadata metadata;
    try {
        metadata = OIDCProviderMetadata.parse(resourceRetriever.retrieveResource(new URL(discoveryUrl)).getContent());
    } catch (IOException | ParseException e) {
        LOGGER.error("Unable to retrieve OAuth provider's metadata.", e);
        return null;
    }
    if (tokenEntry != null && discoveryUrl.equalsIgnoreCase(tokenEntry.getDiscoveryUrl()) && isExpired(tokenEntry.getAccessToken()) && !isExpired(tokenEntry.getRefreshToken())) {
        // refresh token
        return refreshToken(id, sourceId, clientId, clientSecret, discoveryUrl, tokenEntry.getRefreshToken(), metadata);
    }
    // Make a call to get a token
    String encodedClientIdSecret = Base64.getEncoder().encodeToString((clientId + ":" + clientSecret).getBytes(UTF_8));
    return getNewAccessToken(id, sourceId, encodedClientIdSecret, discoveryUrl, grantType, queryParameters, metadata);
}
Also used : TokenEntry(org.codice.ddf.security.token.storage.api.TokenInformation.TokenEntry) OIDCProviderMetadata(com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata) IOException(java.io.IOException) ParseException(com.nimbusds.oauth2.sdk.ParseException) URL(java.net.URL)

Aggregations

TokenEntry (org.codice.ddf.security.token.storage.api.TokenInformation.TokenEntry)6 IOException (java.io.IOException)4 ParseException (com.nimbusds.oauth2.sdk.ParseException)3 OIDCProviderMetadata (com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata)3 URL (java.net.URL)3 Session (org.apache.shiro.session.Session)3 TokenInformation (org.codice.ddf.security.token.storage.api.TokenInformation)3 StopProcessingException (ddf.catalog.plugin.StopProcessingException)2 OAuthFederatedSource (ddf.catalog.source.OAuthFederatedSource)2 Subject (ddf.security.Subject)2 HashMap (java.util.HashMap)2 Map (java.util.Map)2 OAuthServiceException (org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException)2 DISCOVERY_URL (org.codice.ddf.security.token.storage.api.TokenStorage.DISCOVERY_URL)2 VisibleForTesting (com.google.common.annotations.VisibleForTesting)1 Gson (com.google.gson.Gson)1 GsonBuilder (com.google.gson.GsonBuilder)1 DefaultResourceRetriever (com.nimbusds.jose.util.DefaultResourceRetriever)1 ResourceRetriever (com.nimbusds.jose.util.ResourceRetriever)1 Scope (com.nimbusds.oauth2.sdk.Scope)1