mirror of https://github.com/apache/jclouds.git
OAuth filter customization per request
This commit is contained in:
parent
715994b125
commit
624367dfbf
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.jclouds.oauth.v2.config;
|
||||
|
||||
import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE;
|
||||
import static org.jclouds.oauth.v2.config.OAuthProperties.RESOURCE;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.inject.ImplementedBy;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* Provides all OAuth configuration. Implementations are api-specific.
|
||||
*/
|
||||
@Beta
|
||||
@ImplementedBy(OAuthConfigFactory.OAuthConfigFromProperties.class)
|
||||
public interface OAuthConfigFactory {
|
||||
|
||||
@AutoValue
|
||||
public abstract static class OAuthConfig {
|
||||
public abstract List<String> scopes();
|
||||
@Nullable public abstract String audience();
|
||||
@Nullable public abstract String resource();
|
||||
|
||||
public static OAuthConfig create(List<String> scopes, String audience, String resource) {
|
||||
return new AutoValue_OAuthConfigFactory_OAuthConfig(scopes, audience, resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the OAuth configuration to be used to authenticate the gicen
|
||||
* request.
|
||||
*/
|
||||
OAuthConfig forRequest(HttpRequest input);
|
||||
|
||||
public static class OAuthConfigFromProperties implements OAuthConfigFactory {
|
||||
private final OAuthScopes scopes;
|
||||
|
||||
@Inject(optional = true)
|
||||
@Named(AUDIENCE)
|
||||
private String audience;
|
||||
|
||||
@Inject(optional = true)
|
||||
@Named(RESOURCE)
|
||||
private String resource;
|
||||
|
||||
@Inject
|
||||
OAuthConfigFromProperties(OAuthScopes scopes) {
|
||||
this.scopes = scopes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuthConfig forRequest(HttpRequest input) {
|
||||
return OAuthConfig.create(scopes.forRequest(input), audience, resource);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,20 +18,19 @@ package org.jclouds.oauth.v2.filters;
|
|||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
|
||||
import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE;
|
||||
import static org.jclouds.oauth.v2.config.OAuthProperties.RESOURCE;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.http.HttpException;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.location.Provider;
|
||||
import org.jclouds.oauth.v2.AuthorizationApi;
|
||||
import org.jclouds.oauth.v2.config.OAuthScopes;
|
||||
import org.jclouds.oauth.v2.config.OAuthConfigFactory;
|
||||
import org.jclouds.oauth.v2.config.OAuthConfigFactory.OAuthConfig;
|
||||
import org.jclouds.oauth.v2.domain.ClientCredentialsAuthArgs;
|
||||
import org.jclouds.oauth.v2.domain.ClientCredentialsClaims;
|
||||
import org.jclouds.oauth.v2.domain.Token;
|
||||
|
@ -54,22 +53,16 @@ import com.google.common.cache.LoadingCache;
|
|||
public class ClientCredentialsJWTBearerTokenFlow implements OAuthFilter {
|
||||
private static final Joiner ON_SPACE = Joiner.on(" ");
|
||||
|
||||
private final String resource;
|
||||
private final String audience;
|
||||
private final Supplier<Credentials> credentialsSupplier;
|
||||
private final OAuthScopes scopes;
|
||||
private final OAuthConfigFactory oauthConfigFactory;
|
||||
private final LoadingCache<ClientCredentialsAuthArgs, Token> tokenCache;
|
||||
|
||||
@Inject
|
||||
ClientCredentialsJWTBearerTokenFlow(AuthorizeToken loader, @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration,
|
||||
@Provider Supplier<Credentials> credentialsSupplier,
|
||||
OAuthScopes scopes,
|
||||
@Named(AUDIENCE) String audience,
|
||||
@Named(RESOURCE) String resource) {
|
||||
OAuthConfigFactory oauthConfigFactory) {
|
||||
this.credentialsSupplier = credentialsSupplier;
|
||||
this.scopes = scopes;
|
||||
this.audience = audience;
|
||||
this.resource = resource;
|
||||
this.oauthConfigFactory = oauthConfigFactory;
|
||||
// since the session interval is also the token expiration time requested to the server make the token expire a
|
||||
// bit before the deadline to make sure there aren't session expiration exceptions
|
||||
long cacheExpirationSeconds = tokenDuration > 30 ? tokenDuration - 30 : tokenDuration;
|
||||
|
@ -104,11 +97,11 @@ public class ClientCredentialsJWTBearerTokenFlow implements OAuthFilter {
|
|||
}
|
||||
|
||||
@Override public HttpRequest filter(HttpRequest request) throws HttpException {
|
||||
List<String> configuredScopes = scopes.forRequest(request);
|
||||
OAuthConfig oauthConfig = oauthConfigFactory.forRequest(request);
|
||||
ClientCredentialsClaims claims = ClientCredentialsClaims.create( //
|
||||
credentialsSupplier.get().identity, // iss
|
||||
credentialsSupplier.get().identity, // sub
|
||||
audience, // aud
|
||||
oauthConfig.audience(), // aud
|
||||
-1, // placeholder exp for the cache
|
||||
-1, // placeholder nbf for the cache
|
||||
null // placeholder jti for the cache
|
||||
|
@ -116,8 +109,8 @@ public class ClientCredentialsJWTBearerTokenFlow implements OAuthFilter {
|
|||
ClientCredentialsAuthArgs authArgs = ClientCredentialsAuthArgs.create(
|
||||
credentialsSupplier.get().identity,
|
||||
claims,
|
||||
resource == null ? "" : resource,
|
||||
configuredScopes.isEmpty() ? null : ON_SPACE.join(configuredScopes)
|
||||
oauthConfig.resource(),
|
||||
oauthConfig.scopes().isEmpty() ? null : ON_SPACE.join(oauthConfig.scopes())
|
||||
);
|
||||
|
||||
Token token = tokenCache.getUnchecked(authArgs);
|
||||
|
|
|
@ -16,31 +16,28 @@
|
|||
*/
|
||||
package org.jclouds.oauth.v2.filters;
|
||||
|
||||
import java.util.List;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.http.HttpException;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.location.Provider;
|
||||
import org.jclouds.oauth.v2.AuthorizationApi;
|
||||
import org.jclouds.oauth.v2.config.OAuthConfigFactory;
|
||||
import org.jclouds.oauth.v2.config.OAuthConfigFactory.OAuthConfig;
|
||||
import org.jclouds.oauth.v2.domain.ClientSecret;
|
||||
import org.jclouds.oauth.v2.domain.Token;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
|
||||
import org.jclouds.oauth.v2.AuthorizationApi;
|
||||
import org.jclouds.oauth.v2.domain.ClientSecret;
|
||||
import org.jclouds.oauth.v2.config.OAuthScopes;
|
||||
import org.jclouds.oauth.v2.domain.Token;
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.http.HttpException;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.location.Provider;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
|
||||
import static org.jclouds.oauth.v2.config.OAuthProperties.RESOURCE;
|
||||
|
||||
/**
|
||||
* Authorizes new Bearer Tokens at runtime by sending up for the http request.
|
||||
*
|
||||
|
@ -56,16 +53,14 @@ public class ClientCredentialsSecretFlow implements OAuthFilter {
|
|||
|
||||
private final Supplier<Credentials> credentialsSupplier;
|
||||
private final LoadingCache<ClientSecret, Token> tokenCache;
|
||||
private final String resource;
|
||||
private final OAuthScopes scopes;
|
||||
private final OAuthConfigFactory oauthConfigFactory;
|
||||
|
||||
@Inject
|
||||
ClientCredentialsSecretFlow(AuthorizeToken loader, @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration,
|
||||
@Provider Supplier<Credentials> credentialsSupplier, OAuthScopes scopes,
|
||||
@Named(RESOURCE) String resource) {
|
||||
@Provider Supplier<Credentials> credentialsSupplier,
|
||||
OAuthConfigFactory oauthConfigFactory) {
|
||||
this.credentialsSupplier = credentialsSupplier;
|
||||
this.scopes = scopes;
|
||||
this.resource = resource;
|
||||
this.oauthConfigFactory = oauthConfigFactory;
|
||||
// since the session interval is also the token expiration time requested to the server make the token expire a
|
||||
// bit before the deadline to make sure there aren't session expiration exceptions
|
||||
long cacheExpirationSeconds = tokenDuration > 30 ? tokenDuration - 30 : tokenDuration;
|
||||
|
@ -85,12 +80,12 @@ public class ClientCredentialsSecretFlow implements OAuthFilter {
|
|||
}
|
||||
|
||||
@Override public HttpRequest filter(HttpRequest request) throws HttpException {
|
||||
List<String> configuredScopes = scopes.forRequest(request);
|
||||
OAuthConfig oauthConfig = oauthConfigFactory.forRequest(request);
|
||||
ClientSecret client = ClientSecret.create(
|
||||
credentialsSupplier.get().identity,
|
||||
credentialsSupplier.get().credential,
|
||||
resource == null ? "" : resource,
|
||||
configuredScopes.isEmpty() ? null : ON_SPACE.join(configuredScopes)
|
||||
oauthConfig.resource(),
|
||||
oauthConfig.scopes().isEmpty() ? null : ON_SPACE.join(oauthConfig.scopes())
|
||||
);
|
||||
Token token = tokenCache.getUnchecked(client);
|
||||
String authorization = String.format("%s %s", token.tokenType(), token.accessToken());
|
||||
|
|
|
@ -18,7 +18,6 @@ package org.jclouds.oauth.v2.filters;
|
|||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
|
||||
import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
@ -28,7 +27,8 @@ import org.jclouds.http.HttpException;
|
|||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.location.Provider;
|
||||
import org.jclouds.oauth.v2.AuthorizationApi;
|
||||
import org.jclouds.oauth.v2.config.OAuthScopes;
|
||||
import org.jclouds.oauth.v2.config.OAuthConfigFactory;
|
||||
import org.jclouds.oauth.v2.config.OAuthConfigFactory.OAuthConfig;
|
||||
import org.jclouds.oauth.v2.domain.Claims;
|
||||
import org.jclouds.oauth.v2.domain.Token;
|
||||
|
||||
|
@ -51,16 +51,14 @@ import com.google.common.cache.LoadingCache;
|
|||
public class JWTBearerTokenFlow implements OAuthFilter {
|
||||
private static final Joiner ON_COMMA = Joiner.on(",");
|
||||
|
||||
private final String audience;
|
||||
private final Supplier<Credentials> credentialsSupplier;
|
||||
private final OAuthScopes scopes;
|
||||
private final OAuthConfigFactory oauthConfigFactory;
|
||||
private final LoadingCache<TokenCacheKey, Token> tokenCache;
|
||||
|
||||
@Inject JWTBearerTokenFlow(AuthorizeToken loader, @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration,
|
||||
@Provider Supplier<Credentials> credentialsSupplier, OAuthScopes scopes, @Named(AUDIENCE) String audience) {
|
||||
@Provider Supplier<Credentials> credentialsSupplier, OAuthConfigFactory oauthConfigFactory) {
|
||||
this.credentialsSupplier = credentialsSupplier;
|
||||
this.scopes = scopes;
|
||||
this.audience = audience;
|
||||
this.oauthConfigFactory = oauthConfigFactory;
|
||||
// since the session interval is also the token expiration time requested to the server make the token expire a
|
||||
// bit before the deadline to make sure there aren't session expiration exceptions
|
||||
long cacheExpirationSeconds = tokenDuration > 30 ? tokenDuration - 30 : tokenDuration;
|
||||
|
@ -89,10 +87,11 @@ public class JWTBearerTokenFlow implements OAuthFilter {
|
|||
|
||||
@Override public HttpRequest filter(HttpRequest request) throws HttpException {
|
||||
long now = currentTimeSeconds();
|
||||
OAuthConfig oauthConfig = oauthConfigFactory.forRequest(request);
|
||||
Claims claims = Claims.create( //
|
||||
credentialsSupplier.get().identity, // iss
|
||||
ON_COMMA.join(scopes.forRequest(request)), // scope
|
||||
audience, // aud
|
||||
ON_COMMA.join(oauthConfig.scopes()), // scope
|
||||
oauthConfig.audience(), // aud
|
||||
-1, // placeholder exp for the cache
|
||||
-1 // placeholder iat for the cache
|
||||
);
|
||||
|
|
|
@ -17,22 +17,21 @@
|
|||
package org.jclouds.oauth.v2.filters;
|
||||
|
||||
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
|
||||
import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.location.Provider;
|
||||
import org.jclouds.oauth.v2.config.OAuthScopes;
|
||||
import org.jclouds.oauth.v2.config.OAuthConfigFactory;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
|
||||
public class TestJWTBearerTokenFlow extends JWTBearerTokenFlow {
|
||||
|
||||
@Inject TestJWTBearerTokenFlow(AuthorizeToken loader, @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration,
|
||||
@Provider Supplier<Credentials> credentialsSupplier, OAuthScopes scopes, @Named(AUDIENCE) String audience) {
|
||||
super(loader, tokenDuration, credentialsSupplier, scopes, audience);
|
||||
@Provider Supplier<Credentials> credentialsSupplier, OAuthConfigFactory oauthConfigFactory) {
|
||||
super(loader, tokenDuration, credentialsSupplier, oauthConfigFactory);
|
||||
}
|
||||
|
||||
/** Constant time for testing. */
|
||||
|
|
Loading…
Reference in New Issue