mirror of https://github.com/apache/jclouds.git
Fixed OAuth authentication flow injections
This commit is contained in:
parent
0420741690
commit
819141a608
|
@ -16,12 +16,15 @@
|
|||
*/
|
||||
package org.jclouds.oauth.v2.config;
|
||||
|
||||
import static org.jclouds.oauth.v2.config.CredentialType.BEARER_TOKEN_CREDENTIALS;
|
||||
import static org.jclouds.oauth.v2.config.CredentialType.CLIENT_CREDENTIALS_SECRET;
|
||||
import static org.jclouds.oauth.v2.config.CredentialType.P12_PRIVATE_KEY_CREDENTIALS;
|
||||
import static org.jclouds.oauth.v2.config.OAuthProperties.CREDENTIAL_TYPE;
|
||||
import static org.jclouds.rest.config.BinderUtils.bindHttpApi;
|
||||
|
||||
import java.net.URI;
|
||||
import java.security.PrivateKey;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
@ -34,8 +37,10 @@ import org.jclouds.oauth.v2.filters.OAuthFilter;
|
|||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
@ -65,23 +70,23 @@ public final class OAuthModule extends AbstractModule {
|
|||
return CredentialType.fromValue(credentialType);
|
||||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected Map<CredentialType, Class<? extends OAuthFilter>> authenticationFlowMap() {
|
||||
return ImmutableMap.of(P12_PRIVATE_KEY_CREDENTIALS, JWTBearerTokenFlow.class,
|
||||
BEARER_TOKEN_CREDENTIALS, BearerTokenFromCredentials.class,
|
||||
CLIENT_CREDENTIALS_SECRET, ClientCredentialsSecretFlow.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected OAuthFilter authenticationFilterForCredentialType(CredentialType credentialType,
|
||||
JWTBearerTokenFlow serviceAccountAuth,
|
||||
BearerTokenFromCredentials bearerTokenAuth,
|
||||
ClientCredentialsSecretFlow clientCredentialAuth) {
|
||||
switch (credentialType) {
|
||||
case P12_PRIVATE_KEY_CREDENTIALS:
|
||||
return serviceAccountAuth;
|
||||
case BEARER_TOKEN_CREDENTIALS:
|
||||
return bearerTokenAuth;
|
||||
case CLIENT_CREDENTIALS_SECRET:
|
||||
return clientCredentialAuth;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported credential type: " + credentialType);
|
||||
Map<CredentialType, Class<? extends OAuthFilter>> authenticationFlows, Injector injector) {
|
||||
if (!authenticationFlows.containsKey(credentialType)) {
|
||||
throw new IllegalArgumentException("Unsupported credential type: " + credentialType);
|
||||
}
|
||||
return injector.getInstance(authenticationFlows.get(credentialType));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -46,6 +46,19 @@ public interface OAuthScopes {
|
|||
SingleScope() {
|
||||
}
|
||||
}
|
||||
|
||||
@AutoValue public abstract static class NoScopes implements OAuthScopes {
|
||||
public static NoScopes create() {
|
||||
return new AutoValue_OAuthScopes_NoScopes();
|
||||
}
|
||||
|
||||
@Override public List<String> forRequest(HttpRequest input) {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
NoScopes() {
|
||||
}
|
||||
}
|
||||
|
||||
@AutoValue public abstract static class ReadOrWriteScopes implements OAuthScopes {
|
||||
abstract List<String> readScopes();
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
*/
|
||||
package org.jclouds.oauth.v2.domain;
|
||||
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
import org.jclouds.json.SerializedNames;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
|
||||
/**
|
||||
|
@ -34,7 +36,7 @@ public abstract class ClientSecret {
|
|||
public abstract String resource();
|
||||
|
||||
/** The scope(s) to authorize against. **/
|
||||
public abstract String scope();
|
||||
@Nullable public abstract String scope();
|
||||
|
||||
/** When does the token expire. **/
|
||||
public abstract long expire();
|
||||
|
|
|
@ -16,11 +16,14 @@
|
|||
*/
|
||||
package org.jclouds.oauth.v2.filters;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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;
|
||||
|
@ -31,6 +34,7 @@ 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;
|
||||
|
@ -53,13 +57,16 @@ public class ClientCredentialsSecretFlow implements OAuthFilter {
|
|||
private final Supplier<Credentials> credentialsSupplier;
|
||||
private final long tokenDuration;
|
||||
private final LoadingCache<ClientSecret, Token> tokenCache;
|
||||
@Inject(optional = true) @Named(RESOURCE) private String resource;
|
||||
@Inject(optional = true) private OAuthScopes scopes;
|
||||
private final String resource;
|
||||
private final OAuthScopes scopes;
|
||||
|
||||
@Inject
|
||||
ClientCredentialsSecretFlow(AuthorizeToken loader, @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration,
|
||||
@Provider Supplier<Credentials> credentialsSupplier) {
|
||||
@Provider Supplier<Credentials> credentialsSupplier, OAuthScopes scopes,
|
||||
@Named(RESOURCE) String resource) {
|
||||
this.credentialsSupplier = credentialsSupplier;
|
||||
this.scopes = scopes;
|
||||
this.resource = resource;
|
||||
this.tokenDuration = tokenDuration;
|
||||
// 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
|
||||
|
@ -81,11 +88,12 @@ public class ClientCredentialsSecretFlow implements OAuthFilter {
|
|||
|
||||
@Override public HttpRequest filter(HttpRequest request) throws HttpException {
|
||||
long now = currentTimeSeconds();
|
||||
List<String> configuredScopes = scopes.forRequest(request);
|
||||
ClientSecret client = ClientSecret.create(
|
||||
credentialsSupplier.get().identity,
|
||||
credentialsSupplier.get().credential,
|
||||
resource == null ? "" : resource,
|
||||
scopes == null ? null : ON_SPACE.join(scopes.forRequest(request)),
|
||||
configuredScopes.isEmpty() ? null : ON_SPACE.join(configuredScopes),
|
||||
now + tokenDuration
|
||||
);
|
||||
Token token = tokenCache.getUnchecked(client);
|
||||
|
|
|
@ -19,7 +19,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 static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
@ -51,29 +50,17 @@ import com.google.common.cache.LoadingCache;
|
|||
public class JWTBearerTokenFlow implements OAuthFilter {
|
||||
private static final Joiner ON_COMMA = Joiner.on(",");
|
||||
|
||||
@com.google.inject.Inject(optional = true) @Named(AUDIENCE) private String audience;
|
||||
private final String audience;
|
||||
private final Supplier<Credentials> credentialsSupplier;
|
||||
private final OAuthScopes scopes;
|
||||
private final long tokenDuration;
|
||||
private final LoadingCache<Claims, Token> tokenCache;
|
||||
|
||||
public static class TestJWTBearerTokenFlow extends JWTBearerTokenFlow {
|
||||
|
||||
@Inject TestJWTBearerTokenFlow(AuthorizeToken loader, @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration,
|
||||
@Provider Supplier<Credentials> credentialsSupplier, OAuthScopes scopes) {
|
||||
super(loader, tokenDuration, credentialsSupplier, scopes);
|
||||
}
|
||||
|
||||
/** Constant time for testing. */
|
||||
long currentTimeSeconds() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Inject JWTBearerTokenFlow(AuthorizeToken loader, @Named(PROPERTY_SESSION_INTERVAL) long tokenDuration,
|
||||
@Provider Supplier<Credentials> credentialsSupplier, OAuthScopes scopes) {
|
||||
@Provider Supplier<Credentials> credentialsSupplier, OAuthScopes scopes, @Named(AUDIENCE) String audience) {
|
||||
this.credentialsSupplier = credentialsSupplier;
|
||||
this.scopes = scopes;
|
||||
this.audience = audience;
|
||||
this.tokenDuration = tokenDuration;
|
||||
// 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
|
||||
|
@ -94,7 +81,6 @@ public class JWTBearerTokenFlow implements OAuthFilter {
|
|||
}
|
||||
|
||||
@Override public HttpRequest filter(HttpRequest request) throws HttpException {
|
||||
checkNotNull(audience, AUDIENCE);
|
||||
long now = currentTimeSeconds();
|
||||
Claims claims = Claims.create( //
|
||||
credentialsSupplier.get().identity, // iss
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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.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 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);
|
||||
}
|
||||
|
||||
/** Constant time for testing. */
|
||||
long currentTimeSeconds() {
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -70,6 +70,13 @@
|
|||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.jclouds.api</groupId>
|
||||
<artifactId>oauth</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.jclouds</groupId>
|
||||
<artifactId>jclouds-compute</artifactId>
|
||||
|
|
|
@ -38,6 +38,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
|
||||
import org.jclouds.crypto.Crypto;
|
||||
import org.jclouds.oauth.v2.filters.JWTBearerTokenFlow;
|
||||
import org.jclouds.oauth.v2.filters.TestJWTBearerTokenFlow;
|
||||
import org.jclouds.ssh.SshKeys;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
|
@ -67,7 +68,7 @@ enum GoogleComputeEngineTestModule implements Module {
|
|||
|
||||
@Override public void configure(Binder binder) {
|
||||
// Predictable time
|
||||
binder.bind(JWTBearerTokenFlow.class).to(JWTBearerTokenFlow.TestJWTBearerTokenFlow.class);
|
||||
binder.bind(JWTBearerTokenFlow.class).to(TestJWTBearerTokenFlow.class);
|
||||
|
||||
// Predictable ssh keys
|
||||
Crypto crypto = createMock(Crypto.class);
|
||||
|
|
Loading…
Reference in New Issue