Search in sources :

Example 1 with OIDCProviderMetadata

use of com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata 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 OIDCProviderMetadata

use of com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata 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 OIDCProviderMetadata

use of com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata in project ddf by codice.

the class OidcRealm method doGetAuthenticationInfo.

@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    // token is guaranteed to be of type OidcAuthenticationToken by the supports() method
    OidcAuthenticationToken oidcAuthenticationToken = (OidcAuthenticationToken) authenticationToken;
    OidcCredentials credentials = (OidcCredentials) oidcAuthenticationToken.getCredentials();
    OidcConfiguration oidcConfiguration = oidcHandlerConfiguration.getOidcConfiguration();
    OIDCProviderMetadata oidcProviderMetadata = oidcConfiguration.findProviderMetadata();
    WebContext webContext = (WebContext) oidcAuthenticationToken.getContext();
    OidcClient<OidcConfiguration> oidcClient = oidcHandlerConfiguration.getOidcClient(webContext.getFullRequestURL());
    int connectTimeout = oidcHandlerConfiguration.getConnectTimeout();
    int readTimeout = oidcHandlerConfiguration.getReadTimeout();
    try {
        OidcCredentialsResolver oidcCredentialsResolver = new OidcCredentialsResolver(oidcConfiguration, oidcClient, oidcProviderMetadata, connectTimeout, readTimeout);
        oidcCredentialsResolver.resolveIdToken(credentials, webContext);
    } catch (TechnicalException e) {
        throw new AuthenticationException(e);
    }
    // problem getting id token, invalidate credentials
    if (credentials.getIdToken() == null) {
        webContext.getSessionStore().destroySession(webContext);
        String msg = String.format("Could not fetch id token with Oidc credentials (%s). " + "This may be due to the credentials expiring. " + "Invalidating session in order to acquire valid credentials.", credentials);
        LOGGER.warn(msg);
        throw new AuthenticationException(msg);
    }
    OidcProfileCreator oidcProfileCreator = new CustomOidcProfileCreator(oidcConfiguration, oidcClient);
    Optional<UserProfile> userProfile = oidcProfileCreator.create(credentials, webContext);
    SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo();
    simpleAuthenticationInfo.setCredentials(credentials);
    if (userProfile.isPresent()) {
        OidcProfile oidcProfile = (OidcProfile) userProfile.get();
        simpleAuthenticationInfo.setPrincipals(createPrincipalCollectionFromCredentials(oidcProfile));
    } else {
        simpleAuthenticationInfo.setPrincipals(new SimplePrincipalCollection());
    }
    return simpleAuthenticationInfo;
}
Also used : WebContext(org.pac4j.core.context.WebContext) TechnicalException(org.pac4j.core.exception.TechnicalException) UserProfile(org.pac4j.core.profile.UserProfile) SimpleAuthenticationInfo(org.apache.shiro.authc.SimpleAuthenticationInfo) AuthenticationException(org.apache.shiro.authc.AuthenticationException) OidcAuthenticationToken(org.codice.ddf.security.handler.OidcAuthenticationToken) SimplePrincipalCollection(org.apache.shiro.subject.SimplePrincipalCollection) OidcCredentialsResolver(org.codice.ddf.security.oidc.resolver.OidcCredentialsResolver) OidcConfiguration(org.pac4j.oidc.config.OidcConfiguration) OidcCredentials(org.pac4j.oidc.credentials.OidcCredentials) OidcProfileCreator(org.pac4j.oidc.profile.creator.OidcProfileCreator) OidcProfile(org.pac4j.oidc.profile.OidcProfile) OIDCProviderMetadata(com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata)

Example 4 with OIDCProviderMetadata

use of com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata 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)

Example 5 with OIDCProviderMetadata

use of com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata in project ddf by codice.

the class OidcRealmTest method setup.

@Before
public void setup() throws Exception {
    realm = new OidcRealm();
    // Generate the RSA key pair
    KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
    gen.initialize(2048);
    KeyPair keyPair = gen.generateKeyPair();
    RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
    RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
    validAlgorithm = Algorithm.RSA256(publicKey, privateKey);
    invalidAlgorithm = Algorithm.HMAC256("WRONG");
    JWK sigJwk = new RSAKey.Builder(publicKey).privateKey(privateKey).keyUse(KeyUse.SIGNATURE).keyID(UUID.randomUUID().toString()).build();
    String jwk = "{\"keys\": [" + sigJwk.toPublicJWK().toJSONString() + "] }";
    OIDCProviderMetadata oidcProviderMetadata = mock(OIDCProviderMetadata.class);
    when(oidcProviderMetadata.getIDTokenJWSAlgs()).thenReturn(ImmutableList.of(JWSAlgorithm.RS256));
    when(oidcProviderMetadata.getIssuer()).thenReturn(new Issuer("http://localhost:8080/auth/realms/master"));
    when(oidcProviderMetadata.getJWKSetURI()).thenReturn(new URI("http://localhost:8080/auth/realms/master/protocol/openid-connect/certs"));
    ResourceRetriever resourceRetriever = mock(ResourceRetriever.class);
    Resource resource = new Resource(jwk, APPLICATION_JSON);
    when(resourceRetriever.retrieveResource(any())).thenReturn(resource);
    OidcConfiguration configuration = mock(OidcConfiguration.class);
    when(configuration.getClientId()).thenReturn("ddf-client");
    when(configuration.getSecret()).thenReturn("secret");
    when(configuration.isUseNonce()).thenReturn(true);
    when(configuration.getResponseType()).thenReturn("code");
    when(configuration.findProviderMetadata()).thenReturn(oidcProviderMetadata);
    when(configuration.findResourceRetriever()).thenReturn(resourceRetriever);
    OidcHandlerConfiguration handlerConfiguration = mock(OidcHandlerConfiguration.class);
    when(handlerConfiguration.getOidcConfiguration()).thenReturn(configuration);
    when(handlerConfiguration.getOidcClient(any())).thenReturn(mock(OidcClient.class));
    realm.setOidcHandlerConfiguration(handlerConfiguration);
    realm.setUsernameAttributeList(Collections.singletonList("preferred_username"));
    JWT jwt = mock(JWT.class);
    AccessToken accessToken = new BearerAccessToken(getAccessTokenBuilder().sign(validAlgorithm));
    AuthorizationCode authorizationCode = new AuthorizationCode();
    WebContext webContext = getWebContext();
    oidcCredentials = mock(OidcCredentials.class);
    when(oidcCredentials.getIdToken()).thenReturn(jwt);
    when(oidcCredentials.getIdToken()).thenReturn(jwt);
    when(oidcCredentials.getAccessToken()).thenReturn(accessToken);
    when(oidcCredentials.getCode()).thenReturn(authorizationCode);
    authenticationToken = mock(OidcAuthenticationToken.class);
    when(authenticationToken.getCredentials()).thenReturn(oidcCredentials);
    when(authenticationToken.getContext()).thenReturn(webContext);
}
Also used : OidcHandlerConfiguration(org.codice.ddf.security.handler.api.OidcHandlerConfiguration) AuthorizationCode(com.nimbusds.oauth2.sdk.AuthorizationCode) KeyPair(java.security.KeyPair) WebContext(org.pac4j.core.context.WebContext) Issuer(com.nimbusds.oauth2.sdk.id.Issuer) ResourceRetriever(com.nimbusds.jose.util.ResourceRetriever) JWT(com.nimbusds.jwt.JWT) SignedJWT(com.nimbusds.jwt.SignedJWT) Resource(com.nimbusds.jose.util.Resource) OidcAuthenticationToken(org.codice.ddf.security.handler.OidcAuthenticationToken) KeyPairGenerator(java.security.KeyPairGenerator) URI(java.net.URI) OidcConfiguration(org.pac4j.oidc.config.OidcConfiguration) OidcCredentials(org.pac4j.oidc.credentials.OidcCredentials) RSAPublicKey(java.security.interfaces.RSAPublicKey) OidcClient(org.pac4j.oidc.client.OidcClient) AccessToken(com.nimbusds.oauth2.sdk.token.AccessToken) BearerAccessToken(com.nimbusds.oauth2.sdk.token.BearerAccessToken) OIDCProviderMetadata(com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata) BearerAccessToken(com.nimbusds.oauth2.sdk.token.BearerAccessToken) RSAPrivateKey(java.security.interfaces.RSAPrivateKey) JWK(com.nimbusds.jose.jwk.JWK) Before(org.junit.Before)

Aggregations

OIDCProviderMetadata (com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata)5 ParseException (com.nimbusds.oauth2.sdk.ParseException)3 IOException (java.io.IOException)3 URL (java.net.URL)3 TokenEntry (org.codice.ddf.security.token.storage.api.TokenInformation.TokenEntry)3 ResourceRetriever (com.nimbusds.jose.util.ResourceRetriever)2 AccessToken (com.nimbusds.oauth2.sdk.token.AccessToken)2 BearerAccessToken (com.nimbusds.oauth2.sdk.token.BearerAccessToken)2 StopProcessingException (ddf.catalog.plugin.StopProcessingException)2 OAuthFederatedSource (ddf.catalog.source.OAuthFederatedSource)2 Subject (ddf.security.Subject)2 OAuthServiceException (org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException)2 Session (org.apache.shiro.session.Session)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 JWK (com.nimbusds.jose.jwk.JWK)1 DefaultResourceRetriever (com.nimbusds.jose.util.DefaultResourceRetriever)1 Resource (com.nimbusds.jose.util.Resource)1