Search in sources :

Example 1 with OAuthFederatedSource

use of ddf.catalog.source.OAuthFederatedSource in project ddf by codice.

the class OAuthPlugin method getSource.

/**
 * Used to get the {@link OAuthFederatedSource} since we get a proxy.
 *
 * @param source - the proxy
 * @return the matching {@link OAuthFederatedSource}
 */
@VisibleForTesting
OAuthFederatedSource getSource(Source source) {
    Bundle bundle = FrameworkUtil.getBundle(OAuthPlugin.class);
    if (bundle == null) {
        return null;
    }
    BundleContext bundleContext = bundle.getBundleContext();
    if (bundleContext == null) {
        return null;
    }
    OAuthFederatedSource oauthSource;
    try {
        Collection<ServiceReference<OAuthFederatedSource>> implementers = bundleContext.getServiceReferences(OAuthFederatedSource.class, null);
        oauthSource = implementers.stream().map(bundleContext::getService).filter(s -> s.getId().equals(source.getId())).filter(s -> s.getAuthenticationType().equals(OAUTH)).filter(s -> s.getOauthFlow().equals(CODE_FLOW)).findFirst().orElse(null);
    } catch (InvalidSyntaxException e) {
        LOGGER.warn("Error getting source.", e);
        return null;
    }
    return oauthSource;
}
Also used : OAuthFederatedSource(ddf.catalog.source.OAuthFederatedSource) 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) Bundle(org.osgi.framework.Bundle) InvalidSyntaxException(org.osgi.framework.InvalidSyntaxException) BundleContext(org.osgi.framework.BundleContext) ServiceReference(org.osgi.framework.ServiceReference) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Example 2 with OAuthFederatedSource

use of ddf.catalog.source.OAuthFederatedSource 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 3 with OAuthFederatedSource

use of ddf.catalog.source.OAuthFederatedSource 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 4 with OAuthFederatedSource

use of ddf.catalog.source.OAuthFederatedSource in project ddf by codice.

the class OAuthPluginTest method testNoStoredTokensExistingTokenUnderDifferentSourceExpiredTokens.

@Test(expected = OAuthPluginException.class)
public void testNoStoredTokensExistingTokenUnderDifferentSourceExpiredTokens() throws Exception {
    OAuthFederatedSource source = oauthPlugin.oauthSource;
    Subject subject = getSubject();
    QueryRequest input = mock(QueryRequest.class);
    when(input.getProperties()).thenReturn(ImmutableMap.of(SECURITY_SUBJECT, subject));
    String accessToken = getAccessTokenBuilder().withExpiresAt(new Date(Instant.now().minus(1, ChronoUnit.MINUTES).toEpochMilli())).sign(validAlgorithm);
    String refreshToken = getRefreshTokenBuilder().withExpiresAt(new Date(Instant.now().minus(1, ChronoUnit.MINUTES).toEpochMilli())).sign(validAlgorithm);
    TokenInformation.TokenEntry tokenEntry = new TokenInformationImpl.TokenEntryImpl(accessToken, refreshToken, METADATA_ENDPOINT);
    TokenInformation tokenInformation = mock(TokenInformation.class);
    when(tokenInformation.getDiscoveryUrls()).thenReturn(Collections.singleton(METADATA_ENDPOINT));
    when(tokenInformation.getTokenEntries()).thenReturn(Collections.singletonMap("OS", tokenEntry));
    Map<String, Map<String, Object>> stateMap = mock(Map.class);
    when(tokenStorage.getStateMap()).thenReturn(stateMap);
    when(tokenStorage.read(SESSION, SOURCE_ID)).thenReturn(null);
    when(tokenStorage.read(SESSION)).thenReturn(tokenInformation);
    try {
        oauthPlugin.process(source, input);
    } catch (OAuthPluginException e) {
        assertEquals(e.getSourceId(), CSW_SOURCE);
        assertEquals(e.getErrorType().getStatusCode(), 401);
        ArgumentCaptor<Map<String, Object>> captor = ArgumentCaptor.forClass(Map.class);
        verify(stateMap, times(1)).put(anyString(), captor.capture());
        assertUrl(e, captor.getValue());
        throw e;
    }
}
Also used : OAuthFederatedSource(ddf.catalog.source.OAuthFederatedSource) ArgumentCaptor(org.mockito.ArgumentCaptor) QueryRequest(ddf.catalog.operation.QueryRequest) TokenInformation(org.codice.ddf.security.token.storage.api.TokenInformation) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) Subject(ddf.security.Subject) Date(java.util.Date) OAuthPluginException(ddf.catalog.plugin.OAuthPluginException) JSONObject(net.minidev.json.JSONObject) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) Test(org.junit.Test)

Example 5 with OAuthFederatedSource

use of ddf.catalog.source.OAuthFederatedSource in project ddf by codice.

the class OAuthPluginTest method testProcess.

@Test
public void testProcess() throws Exception {
    OAuthFederatedSource source = oauthPlugin.oauthSource;
    Subject subject = getSubject();
    QueryRequest input = mock(QueryRequest.class);
    when(input.getProperties()).thenReturn(ImmutableMap.of(SECURITY_SUBJECT, subject));
    String accessToken = getAccessTokenBuilder().sign(validAlgorithm);
    TokenInformation.TokenEntry tokenEntry = new TokenInformationImpl.TokenEntryImpl(accessToken, "refresh_token", METADATA_ENDPOINT);
    when(tokenStorage.read(SESSION, CSW_SOURCE)).thenReturn(tokenEntry);
    QueryRequest output = oauthPlugin.process(source, input);
    assertEquals(input, output);
}
Also used : OAuthFederatedSource(ddf.catalog.source.OAuthFederatedSource) QueryRequest(ddf.catalog.operation.QueryRequest) TokenInformation(org.codice.ddf.security.token.storage.api.TokenInformation) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) Subject(ddf.security.Subject) Test(org.junit.Test)

Aggregations

OAuthFederatedSource (ddf.catalog.source.OAuthFederatedSource)10 Subject (ddf.security.Subject)10 QueryRequest (ddf.catalog.operation.QueryRequest)9 TokenInformation (org.codice.ddf.security.token.storage.api.TokenInformation)9 OAuthPluginException (ddf.catalog.plugin.OAuthPluginException)7 Map (java.util.Map)7 Test (org.junit.Test)7 ArgumentMatchers.anyString (org.mockito.ArgumentMatchers.anyString)7 ImmutableMap (com.google.common.collect.ImmutableMap)5 Date (java.util.Date)5 ParseException (com.nimbusds.oauth2.sdk.ParseException)3 OIDCProviderMetadata (com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata)3 StopProcessingException (ddf.catalog.plugin.StopProcessingException)3 IOException (java.io.IOException)3 URL (java.net.URL)3 Form (javax.ws.rs.core.Form)3 Response (javax.ws.rs.core.Response)3 OAuthServiceException (org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException)3 Session (org.apache.shiro.session.Session)3 TokenEntry (org.codice.ddf.security.token.storage.api.TokenInformation.TokenEntry)3