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;
}
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);
}
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;
}
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;
}
}
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);
}
Aggregations