mirror of https://github.com/apache/jclouds.git
made oauth throw AuthorizationException on GeneralSecurityExceptioon and IllegalArgumentException
This commit is contained in:
parent
6dc03a7993
commit
310aee2d01
|
@ -16,10 +16,30 @@
|
||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jclouds.oauth.v2.functions;
|
package org.jclouds.oauth.v2.functions;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
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 com.google.common.util.concurrent.UncheckedExecutionException;
|
||||||
|
import org.jclouds.domain.Credentials;
|
||||||
|
import org.jclouds.location.Provider;
|
||||||
|
import org.jclouds.oauth.v2.domain.OAuthCredentials;
|
||||||
|
import org.jclouds.rest.AuthorizationException;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Named;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.security.KeyFactory;
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static com.google.common.base.Preconditions.checkState;
|
|
||||||
import static com.google.common.base.Throwables.propagate;
|
import static com.google.common.base.Throwables.propagate;
|
||||||
import static java.lang.String.format;
|
import static java.lang.String.format;
|
||||||
import static org.jclouds.crypto.Pems.privateKeySpec;
|
import static org.jclouds.crypto.Pems.privateKeySpec;
|
||||||
|
@ -27,31 +47,12 @@ import static org.jclouds.io.Payloads.newStringPayload;
|
||||||
import static org.jclouds.oauth.v2.OAuthConstants.NO_ALGORITHM;
|
import static org.jclouds.oauth.v2.OAuthConstants.NO_ALGORITHM;
|
||||||
import static org.jclouds.oauth.v2.OAuthConstants.OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES;
|
import static org.jclouds.oauth.v2.OAuthConstants.OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES;
|
||||||
import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM;
|
import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM;
|
||||||
|
import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
|
||||||
import java.io.IOException;
|
|
||||||
import java.security.KeyFactory;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.spec.InvalidKeySpecException;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Named;
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
import org.jclouds.domain.Credentials;
|
|
||||||
import org.jclouds.location.Provider;
|
|
||||||
import org.jclouds.oauth.v2.domain.OAuthCredentials;
|
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
|
||||||
import com.google.common.base.Supplier;
|
|
||||||
import com.google.common.cache.CacheBuilder;
|
|
||||||
import com.google.common.cache.CacheLoader;
|
|
||||||
import com.google.common.cache.LoadingCache;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads {@link OAuthCredentials} from a pem private key using the KeyFactory obtained from the JWT Algorithm
|
* Loads {@link OAuthCredentials} from a pem private key using the KeyFactory obtained from the JWT Algorithm
|
||||||
* Name<->KeyFactory name mapping in OAuthConstants. The pem pk algorithm must match the KeyFactory algorithm.
|
* Name<->KeyFactory name mapping in OAuthConstants. The pem pk algorithm must match the KeyFactory algorithm.
|
||||||
*
|
*
|
||||||
* @author David Alves
|
* @author David Alves
|
||||||
* @see org.jclouds.oauth.v2.OAuthConstants#OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES
|
* @see org.jclouds.oauth.v2.OAuthConstants#OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES
|
||||||
*/
|
*/
|
||||||
|
@ -63,10 +64,10 @@ public class OAuthCredentialsSupplier implements Supplier<OAuthCredentials> {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public OAuthCredentialsSupplier(@Provider Supplier<Credentials> creds, OAuthCredentialsForCredentials loader,
|
public OAuthCredentialsSupplier(@Provider Supplier<Credentials> creds, OAuthCredentialsForCredentials loader,
|
||||||
@Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm) {
|
@Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm) {
|
||||||
this.creds = creds;
|
this.creds = creds;
|
||||||
checkState(OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES.containsKey(signatureOrMacAlgorithm),
|
checkArgument(OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES.containsKey(signatureOrMacAlgorithm),
|
||||||
format("No mapping for key factory for algorithm: %s", signatureOrMacAlgorithm));
|
format("No mapping for key factory for algorithm: %s", signatureOrMacAlgorithm));
|
||||||
// throw out the private key related to old credentials
|
// throw out the private key related to old credentials
|
||||||
this.keyCache = CacheBuilder.newBuilder().maximumSize(2).build(checkNotNull(loader, "loader"));
|
this.keyCache = CacheBuilder.newBuilder().maximumSize(2).build(checkNotNull(loader, "loader"));
|
||||||
}
|
}
|
||||||
|
@ -82,7 +83,7 @@ public class OAuthCredentialsSupplier implements Supplier<OAuthCredentials> {
|
||||||
@Inject
|
@Inject
|
||||||
public OAuthCredentialsForCredentials(@Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm) {
|
public OAuthCredentialsForCredentials(@Named(SIGNATURE_OR_MAC_ALGORITHM) String signatureOrMacAlgorithm) {
|
||||||
this.keyFactoryAlgorithm = OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES.get(checkNotNull(
|
this.keyFactoryAlgorithm = OAUTH_ALGORITHM_NAMES_TO_KEYFACTORY_ALGORITHM_NAMES.get(checkNotNull(
|
||||||
signatureOrMacAlgorithm, "signatureOrMacAlgorithm"));
|
signatureOrMacAlgorithm, "signatureOrMacAlgorithm"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -96,20 +97,31 @@ public class OAuthCredentialsSupplier implements Supplier<OAuthCredentials> {
|
||||||
KeyFactory keyFactory = KeyFactory.getInstance(keyFactoryAlgorithm);
|
KeyFactory keyFactory = KeyFactory.getInstance(keyFactoryAlgorithm);
|
||||||
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec(newStringPayload(privateKeyInPemFormat)));
|
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec(newStringPayload(privateKeyInPemFormat)));
|
||||||
return new OAuthCredentials.Builder().identity(identity).credential(privateKeyInPemFormat)
|
return new OAuthCredentials.Builder().identity(identity).credential(privateKeyInPemFormat)
|
||||||
.privateKey(privateKey).build();
|
.privateKey(privateKey).build();
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
throw propagate(e);
|
|
||||||
} catch (InvalidKeySpecException e) {
|
|
||||||
throw propagate(e);
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw propagate(e);
|
throw propagate(e);
|
||||||
|
// catch security exceptions InvalidKeySpecException and NoSuchAlgorithmException as GSE
|
||||||
|
} catch (GeneralSecurityException e) {
|
||||||
|
throw new AuthorizationException("security exception loading credentials. " + e.getMessage(), e);
|
||||||
|
// catch IAE that is thrown when parsing the pk fails
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new AuthorizationException("cannot parse pk. " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OAuthCredentials get() {
|
public OAuthCredentials get() {
|
||||||
return keyCache.getUnchecked(checkNotNull(creds.get(), "credential supplier returned null"));
|
try {
|
||||||
|
// loader always throws UncheckedExecutionException so no point in using get()
|
||||||
|
return keyCache.getUnchecked(checkNotNull(creds.get(), "credential supplier returned null"));
|
||||||
|
} catch (UncheckedExecutionException e) {
|
||||||
|
Throwable authorizationException = getFirstThrowableOfType(e, AuthorizationException.class);
|
||||||
|
if (authorizationException != null) {
|
||||||
|
throw ((AuthorizationException) authorizationException);
|
||||||
|
}
|
||||||
|
throw propagate(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. jclouds 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.functions;
|
||||||
|
|
||||||
|
import com.google.common.base.Suppliers;
|
||||||
|
import org.jclouds.domain.Credentials;
|
||||||
|
import org.jclouds.oauth.v2.OAuthTestUtils;
|
||||||
|
import org.jclouds.rest.AuthorizationException;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import static org.jclouds.oauth.v2.functions.OAuthCredentialsSupplier.OAuthCredentialsForCredentials;
|
||||||
|
import static org.testng.Assert.assertNotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author David Alves
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit")
|
||||||
|
public class OAuthCredentialsSupplierTest {
|
||||||
|
|
||||||
|
@Test(expectedExceptions = AuthorizationException.class)
|
||||||
|
public void testAuthorizationExceptionIsThrownOnBadKeys() {
|
||||||
|
OAuthCredentialsSupplier supplier = new OAuthCredentialsSupplier(Suppliers.ofInstance(new Credentials("MOMMA",
|
||||||
|
"MIA")), new OAuthCredentialsForCredentials("RS256"), "RS256");
|
||||||
|
supplier.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||||
|
public void testGSEChildExceptionsPropagateAsAuthorizationException() {
|
||||||
|
OAuthCredentialsSupplier supplier = new OAuthCredentialsSupplier(Suppliers.ofInstance(new Credentials("MOMMA",
|
||||||
|
"MIA")), new OAuthCredentialsForCredentials("MOMMA"), "MOMMA");
|
||||||
|
supplier.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCredentialsAreLoadedOnRightAlgoAndCredentials() {
|
||||||
|
Properties propertied = OAuthTestUtils.defaultProperties(new Properties());
|
||||||
|
Credentials validCredentials = new Credentials(propertied.getProperty("oauth.identity"),
|
||||||
|
propertied.getProperty("oauth.credential"));
|
||||||
|
OAuthCredentialsSupplier supplier = new OAuthCredentialsSupplier(Suppliers.ofInstance(validCredentials),
|
||||||
|
new OAuthCredentialsForCredentials("RS256"), "RS256");
|
||||||
|
assertNotNull(supplier.get());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue