This commit is contained in:
Ryan Baxter
2017-01-26 19:58:49 -05:00
9 changed files with 843 additions and 0 deletions

View File

@@ -307,6 +307,8 @@ start successfully with a misconfigured or invalid configuration source and
not detect an error until an application requests configuration from that
configuration source.
===== Authentication
To use HTTP basic authentication on the remote repository add the
"username" and "password" properties separately (not in the URL),
e.g.
@@ -337,6 +339,28 @@ TIP: If you don't know where your `~/.git` directory is us `git config
--global` to manipulate the settings (e.g. `git config --global
http.sslVerify false`).
===== Authentication with AWS CodeCommit
http://docs.aws.amazon.com/codecommit/latest/userguide/welcome.html[AWS CodeCommit] authentication can also be
done. AWS CodeCommit uses an authentication helper when using Git from the command line. This helper is not
used with the JGit library, so a JGit CredentialProvider for AWS CodeCommit will be created if the Git
URI matches the AWS CodeCommit pattern. AWS CodeCommit URIs always look like
https://git-codecommit.${AWS_REGION}.amazonaws.com/${repopath}.
If you provide a username and password with an AWS CodeCommit URI, then these must be
the http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSGettingStartedGuide/AWSCredentials.html[AWS accessKeyId and secretAccessKey]
to be used to access the repository. If you do not specify a username and password,
then the accessKeyId and secretAccessKey will be retrieved using the
http://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html[AWS Default Credential Provider Chain].
If your Git URI matches the CodeCommit URI pattern (above) then you must provide
valid AWS credentials in the username and password, or in one of the locations supported
by the default credential provider chain. AWS EC2 instances may use
http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html[IAM Roles for EC2 Instances].
Note: The aws-java-sdk-core jar is an optional dependency. If the aws-java-sdk-core jar is not on your
classpath, then the AWS Code Commit credential provider will not be created regardless of the git server URI.
===== Placeholders in Git Search Paths
Spring Cloud Config Server also supports a search path with

View File

@@ -60,6 +60,12 @@
<artifactId>svnkit</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-core</artifactId>
<version>1.11.52</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

View File

@@ -39,6 +39,7 @@ import org.eclipse.jgit.api.TransportCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.RefNotFoundException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.FetchResult;
import org.eclipse.jgit.transport.JschConfigSessionFactory;
import org.eclipse.jgit.transport.OpenSshConfig.Host;
@@ -89,6 +90,11 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
private JGitEnvironmentRepository.JGitFactory gitFactory = new JGitEnvironmentRepository.JGitFactory();
private String defaultLabel = DEFAULT_LABEL;
/**
* The credentials provider to use to connect to the Git repository.
*/
private CredentialsProvider gitCredentialsProvider;
/**
* Flag to indicate that the repository should force pull. If true discard any local
@@ -494,4 +500,18 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
return command;
}
}
/**
* @return the gitCredentialsProvider
*/
public CredentialsProvider getGitCredentialsProvider() {
return gitCredentialsProvider;
}
/**
* @param gitCredentialsProvider the gitCredentialsProvider to set
*/
public void setGitCredentialsProvider(CredentialsProvider gitCredentialsProvider) {
this.gitCredentialsProvider = gitCredentialsProvider;
}
}

View File

@@ -27,6 +27,7 @@ import java.util.Map;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.server.credentials.GitCredentialsProviderFactory;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.util.PatternMatchUtils;
import org.springframework.util.StringUtils;
@@ -61,6 +62,8 @@ public class MultipleJGitEnvironmentRepository extends JGitEnvironmentRepository
@Override
public void afterPropertiesSet() throws Exception {
GitCredentialsProviderFactory credentialFactory = new GitCredentialsProviderFactory();
super.setGitCredentialsProvider(credentialFactory.createFor(getUri(), getUsername(), getPassword()));
super.afterPropertiesSet();
for (String name : this.repos.keySet()) {
PatternMatchingJGitEnvironmentRepository repo = this.repos.get(name);
@@ -74,6 +77,13 @@ public class MultipleJGitEnvironmentRepository extends JGitEnvironmentRepository
if (getTimeout() != 0 && repo.getTimeout() == 0) {
repo.setTimeout(getTimeout());
}
String user = repo.getUsername();
String pass = repo.getPassword();
if (user == null) {
user = getUsername();
pass = getPassword();
}
repo.setGitCredentialsProvider(credentialFactory.createFor(repo.getUri(), user, pass));
repo.afterPropertiesSet();
}
}

View File

@@ -0,0 +1,392 @@
/*
* Copyright 2013-2015 the original author or authors.
*
* Licensed 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.springframework.cloud.config.server.credentials;
import static org.springframework.util.StringUtils.hasText;
import java.net.URI;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jgit.errors.UnsupportedCredentialItem;
import org.eclipse.jgit.transport.CredentialItem;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.URIish;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.AWSSessionCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
import com.amazonaws.util.ValidationUtils;
/**
* Provides a jgit {@link CredentialsProvider} implementation that can provide
* the appropriate credentials to connect to an AWS CodeCommit repository.
* <p>
* From the command line, you can configure git to use AWS code commit with a
* credential helper. However, jgit does not support credential helper commands,
* but it does provider a CredentialsProvider abstract class we can extend.
* </p>
* Connecting to an AWS CodeCommit (codecommit) repository requires an AWS access key
* and secret key. These are used to calculate a signature for the git request. The
* AWS access key is used as the codecommit username, and the calculated signature
* is used as the password. The process for calculating this signature is documented
* very well at http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html.
* </p>
*
* @author Don Laidlaw
*
*/
public class AwsCodeCommitCredentialProvider extends CredentialsProvider {
private static final String SHA_256 = "SHA-256"; //$NON-NLS-1$
private static final String UTF8 = "UTF8"; //$NON-NLS-1$
private static final String HMAC_SHA256 = "HmacSHA256"; //$NON-NLS-1$
private static final char[] hexArray = "0123456789abcdef".toCharArray(); //$NON-NLS-1$
protected Log logger = LogFactory.getLog(getClass());
/**
* The AWSCredentialsProvider will be used to provide the access key and
* secret key if they are not specified.
*/
private AWSCredentialsProvider awsCredentialProvider;
/**
* If the access and secret keys are provided, then the
* AWSCredentialsProvider will not be used. The username is the
* awsAccessKeyId.
*/
private String username;
/**
* If the access and secret keys are provided, then the AWSCredentialsProvider will
* not be used. The password is the awsSecretKey.
*/
private String password;
/**
* This credentials provider cannot run interactively.
* @return false
* @see org.eclipse.jgit.transport.CredentialsProvider#isInteractive()
*/
@Override
public boolean isInteractive() {
return false;
}
/**
* We support username and password credential items only.
* @see org.eclipse.jgit.transport.CredentialsProvider#supports(org.eclipse.jgit.transport.CredentialItem[])
*/
@Override
public boolean supports(CredentialItem... items) {
for (CredentialItem i : items) {
if (i instanceof CredentialItem.Username) {
continue;
}
else if (i instanceof CredentialItem.Password) {
continue;
}
else {
return false;
}
}
return true;
}
/**
* Get the AWSCredentials. If an AWSCredentialProvider was specified, use that, otherwise,
* create a new AWSCredentialsProvider. If the username and password are provided, then
* use those directly as AWSCredentials. Otherwise us the {@link DefaultAWSCredentialsProviderChain}
* as is standard with AWS applications.
* @return the AWS credentials.
*/
private AWSCredentials retrieveAwsCredentials() {
if (awsCredentialProvider == null) {
if (username != null && password != null) {
logger.debug("Creating a static AWSCredentialsProvider");
awsCredentialProvider = new AWSStaticCredentialsProvider(new BasicAWSCredentials(username, password));
} else {
logger.debug("Creating a default AWSCredentialsProvider");
awsCredentialProvider = new DefaultAWSCredentialsProviderChain();
}
}
return awsCredentialProvider.getCredentials();
}
/**
* Get the username and password to use for the given uri.
* @see org.eclipse.jgit.transport.CredentialsProvider#get(org.eclipse.jgit.transport.URIish, org.eclipse.jgit.transport.CredentialItem[])
*/
@Override
public boolean get(URIish uri, CredentialItem... items) throws UnsupportedCredentialItem {
String codeCommitPassword;
String awsAccessKey;
String awsSecretKey;
try {
AWSCredentials awsCredentials = retrieveAwsCredentials();
StringBuilder awsKey = new StringBuilder();
awsKey.append(awsCredentials.getAWSAccessKeyId());
awsSecretKey = awsCredentials.getAWSSecretKey();
if (awsCredentials instanceof AWSSessionCredentials) {
AWSSessionCredentials sessionCreds = (AWSSessionCredentials) awsCredentials;
if (sessionCreds.getSessionToken() != null) {
awsKey.append('%')
.append(sessionCreds.getSessionToken());
}
}
awsAccessKey = awsKey.toString();
} catch (Throwable t) {
logger.warn("Unable to retrieve AWS Credentials", t);
return false;
}
try {
codeCommitPassword = calculateCodeCommitPassword(uri, awsSecretKey);
} catch (Throwable t) {
logger.warn("Error calculating the AWS CodeCommit password", t);
return false;
}
for (CredentialItem i : items) {
if (i instanceof CredentialItem.Username) {
((CredentialItem.Username) i).setValue(awsAccessKey);
logger.trace("Returning username " + awsAccessKey);
continue;
}
if (i instanceof CredentialItem.Password) {
((CredentialItem.Password) i).setValue(codeCommitPassword.toCharArray());
logger.trace("Returning password " + codeCommitPassword);
continue;
}
if (i instanceof CredentialItem.StringType && i.getPromptText().equals("Password: ")) { //$NON-NLS-1$
((CredentialItem.StringType) i).setValue(codeCommitPassword);
logger.trace("Returning password string " + codeCommitPassword);
continue;
}
throw new UnsupportedCredentialItem(uri, i.getClass().getName() + ":" + i.getPromptText()); //$NON-NLS-1$
}
return true;
}
/**
* Calculate the AWS CodeCommit password for the provided URI and AWS secret key.
* This uses the algorithm published by AWS at
* http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html
* @param uri the codecommit repository uri
* @param awsSecretKey the aws secret key
* @return the password to use in the git request
*/
protected static String calculateCodeCommitPassword(URIish uri, String awsSecretKey) {
String[] split = uri.getHost().split("\\.");
if (split.length < 4) {
throw new CredentialException("Cannot detect AWS region from URI", null);
}
String region = split[1];
Date now = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
String dateStamp = dateFormat.format(now);
String shortDateStamp = dateStamp.substring(0, 8);
String codeCommitPassword;
try {
StringBuilder stringToSign = new StringBuilder();
stringToSign.append("AWS4-HMAC-SHA256\n")
.append(dateStamp).append("\n")
.append(shortDateStamp)
.append("/").append(region)
.append("/codecommit/aws4_request\n")
.append(bytesToHexString(canonicalRequestDigest(uri)));
byte[] signedRequest = sign(awsSecretKey, shortDateStamp, region, stringToSign.toString());
codeCommitPassword = dateStamp + "Z" + bytesToHexString(signedRequest);
} catch (Exception e) {
throw new CredentialException("Error calculating AWS CodeCommit password", e);
}
return codeCommitPassword;
}
/**
* Throw out cached data and force retrieval of AWS credentials.
* @param uri This parameter is not used in this implementation.
*/
@Override
public void reset(URIish uri) {
// Should throw out cached info.
// Note that even though the credentials (password) we calculate here is
// valid for 15 minutes, we do not cache it. Instead we just re-calculate
// it each time we need it. However, the AWSCredentialProvider will cache
// its AWSCredentials object.
}
private static byte[] hmacSha256(String data, byte[] key) throws Exception {
String algorithm = HMAC_SHA256;
Mac mac = Mac.getInstance(algorithm);
mac.init(new SecretKeySpec(key, algorithm));
return mac.doFinal(data.getBytes(UTF8));
}
private static byte[] sign(String secret, String shortDateStamp, String region, String toSign) throws Exception {
byte[] kSecret = ("AWS4" + secret).getBytes(UTF8);
byte[] kDate = hmacSha256(shortDateStamp, kSecret);
byte[] kRegion = hmacSha256(region, kDate);
byte[] kService = hmacSha256("codecommit", kRegion);
byte[] kSigning = hmacSha256("aws4_request", kService);
return hmacSha256(toSign, kSigning);
}
/**
* Creates a message digest
* @param uri
* @return
* @throws NoSuchAlgorithmException
*/
private static byte[] canonicalRequestDigest(URIish uri) throws NoSuchAlgorithmException {
StringBuilder canonicalRequest = new StringBuilder();
canonicalRequest.append("GIT\n") // codecommit uses GIT as the request method
.append(uri.getPath()).append("\n") // URI request path
.append("\n") // Query string, always empty for codecommit
// Next is canonical headers, codecommit only requires the host header
.append("host:").append(uri.getHost()).append("\n")
.append("\n") // canonical headers are always terminated by newline
.append("host\n"); // The list of canonical headers, only one for codecommit
MessageDigest digest = MessageDigest.getInstance(SHA_256);
return digest.digest(canonicalRequest.toString().getBytes());
}
/**
* Convert bytes to a hex string
* @param bytes the bytes
* @return a string of hex characters encoding the bytes.
*/
private static String bytesToHexString(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
/**
* @return the awsCredentialProvider
*/
public AWSCredentialsProvider getAwsCredentialProvider() {
return awsCredentialProvider;
}
/**
* @param awsCredentialProvider the awsCredentialProvider to set
*/
public void setAwsCredentialProvider(AWSCredentialsProvider awsCredentialProvider) {
this.awsCredentialProvider = awsCredentialProvider;
}
/**
* This provider can handle uris like https://git-codecommit.$AWS_REGION.amazonaws.com/v1/repos/$REPO
* @see org.springframework.cloud.config.server.credentials.GitCredentialsProvider#canHandleUri(java.lang.String)
*/
public static boolean canHandle(String uri) {
if (!hasText(uri)) {
return false;
}
try {
URI u = new URI(uri.toLowerCase());
if (u.getScheme().equals("https")) {
String host = u.getHost();
if (host.endsWith(".amazonaws.com") && host.startsWith("git-codecommit.")) {
return true;
}
}
} catch (Throwable t) {
// ignore all, we can't handle it
}
return false;
}
/**
* @return the username
*/
public String getUsername() {
return username;
}
/**
* @param username the username to set
*/
public void setUsername(String username) {
this.username = username;
}
/**
* @return the password
*/
public String getPassword() {
return password;
}
/**
* @param password the password to set
*/
public void setPassword(String password) {
this.password = password;
}
/**
* Simple implementation of AWSCredentialsProvider that just wraps static AWSCredentials.
* AWS Actually provides this class in newer versions of the AWS API.
*/
public class AWSStaticCredentialsProvider implements AWSCredentialsProvider {
private final AWSCredentials credentials;
public AWSStaticCredentialsProvider(AWSCredentials credentials) {
this.credentials = ValidationUtils.assertNotNull(credentials, "credentials");
}
public AWSCredentials getCredentials() {
return credentials;
}
public void refresh() {
// Nothing to do for static credentials.
}
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2013-2015 the original author or authors.
*
* Licensed 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.springframework.cloud.config.server.credentials;
/**
* @author Don Laidlaw
*
*/
@SuppressWarnings("serial")
public class CredentialException extends RuntimeException {
/**
*
*/
public CredentialException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright 2013-2015 the original author or authors.
*
* Licensed 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.springframework.cloud.config.server.credentials;
import static org.springframework.util.StringUtils.hasText;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.springframework.util.ClassUtils;
/**
* A CredentialsProvider factory for Git repositories. Can handle AWS CodeCommit
* repositories and other repositories with username/password.
*
* @author Don Laidlaw
*
*/
public class GitCredentialsProviderFactory {
protected Log logger = LogFactory.getLog(getClass());
/**
* Enable the AWS Code Commit credentials provider for Git URI's
* that match the AWS Code Commit pattern of
* https://git-codecommit.${AWS_REGION}.amazonaws.com/${repoPath}.
* Enabled by default.
*/
protected boolean awsCodeCommitEnabled = true;
/**
* Search for a credential provider that will handle the specified URI. If
* not found, and the username has text, then create a default using the
* provided username and password. Otherwise null.
* @param uri the URI of the repository (cannot be null)
* @param username the username provided for the repository (may be null)
* @param password the password provided for the repository (may be null)
* @return the first matched credentials provider or the default or null.
*/
public CredentialsProvider createFor(String uri, String username, String password) {
CredentialsProvider provider = null;
if (awsAvailable() && AwsCodeCommitCredentialProvider.canHandle(uri)) {
logger.debug("Constructing AwsCodeCommitCredentialProvider for URI " + uri);
AwsCodeCommitCredentialProvider aws = new AwsCodeCommitCredentialProvider();
aws.setUsername(username);
aws.setPassword(password);
provider = aws;
}
else if (hasText(username)) {
logger.debug("Constructing UsernamePasswordCredentialsProvider for URI " + uri);
provider = new UsernamePasswordCredentialsProvider(username, password.toCharArray());
}
else {
logger.debug("No credentials provider required for URI " + uri);
}
return provider;
}
/**
* Check to see if the AWS Authentication API is available.
* @return true if the com.amazonaws.auth.DefaultAWSCredentialsProviderChain is present,
* false otherwise.
*/
private boolean awsAvailable() {
return awsCodeCommitEnabled
&& ClassUtils.isPresent("com.amazonaws.auth.DefaultAWSCredentialsProviderChain", null);
}
/**
* @return the awsCodeCommitEnabled
*/
public boolean isAwsCodeCommitEnabled() {
return awsCodeCommitEnabled;
}
/**
* @param awsCodeCommitEnabled the awsCodeCommitEnabled to set
*/
public void setAwsCodeCommitEnabled(boolean awsCodeCommitEnabled) {
this.awsCodeCommitEnabled = awsCodeCommitEnabled;
}
}

View File

@@ -0,0 +1,147 @@
/*
* Copyright 2013-2015 the original author or authors.
*
* Licensed 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.springframework.cloud.config.server.credentials;
import static org.junit.Assert.*;
import java.net.URISyntaxException;
import org.eclipse.jgit.errors.UnsupportedCredentialItem;
import org.eclipse.jgit.transport.CredentialItem;
import org.eclipse.jgit.transport.URIish;
import org.junit.Before;
import org.junit.Test;
import com.amazonaws.auth.AWSCredentialsProvider;
/**
* It would be nice to do an integration test, however, this would require
* using real AWS credentials. How can we test the credential generation
* without real credentials?
*
* @author don laidlaw
*
*/
public class AwsCodeCommitCredentialsProviderTests {
private static final String PASSWORD = "secret";
private static final String USER = "test";
private static final String AWS_REPO = "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/test";
private static final String BAD_REPO = "https://amazonaws.com/v1/repos/test";
private AwsCodeCommitCredentialProvider provider;
@Before
public void init() {
GitCredentialsProviderFactory factory = new GitCredentialsProviderFactory();
provider = (AwsCodeCommitCredentialProvider)
factory.createFor(AWS_REPO, USER, PASSWORD);
}
@Test
public void basics() {
assertNotNull(provider);
assertEquals(USER, provider.getUsername());
assertEquals(PASSWORD, provider.getPassword());
assertFalse(provider.isInteractive());
}
@Test
public void testSupportsUsernamePassword() {
assertTrue(provider.supports(new CredentialItem[] {
new CredentialItem.Username(),
new CredentialItem.Password()
}));
}
@Test
public void testNotSupportsOther() {
assertFalse(provider.supports(new CredentialItem[] {
new CredentialItem.YesNoType("OK To Login?") // this is not ok
}));
assertFalse(provider.supports(new CredentialItem[] {
new CredentialItem.StringType("OK To Login?", true) // this is not ok
}));
assertFalse(provider.supports(new CredentialItem[] {
new CredentialItem.Username(), // this is ok
new CredentialItem.Password(), // this is ok
new CredentialItem.StringType("OK To Login?", true) // this is not ok
}));
}
@Test
public void testAwsCredentialsProviderIsNullInitially() {
AWSCredentialsProvider awsProvider = provider.getAwsCredentialProvider();
assertNull(awsProvider);
}
@Test
public void testAwsCredentialsProviderIsDefinedAfterGet() throws URISyntaxException {
AWSCredentialsProvider awsProvider = provider.getAwsCredentialProvider();
assertNull(awsProvider);
assertTrue(provider.get(new URIish(AWS_REPO), makeCredentialItems()));
awsProvider = provider.getAwsCredentialProvider();
assertNotNull(awsProvider);
assertTrue(awsProvider instanceof AwsCodeCommitCredentialProvider.AWSStaticCredentialsProvider);
}
@Test
public void testBadUriReturnsFalse() throws UnsupportedCredentialItem, URISyntaxException {
CredentialItem[] credentialItems = makeCredentialItems();
assertFalse(provider.get(new URIish(BAD_REPO), credentialItems));
}
@Test
public void testThrowsUnsupportedCredentialException() throws URISyntaxException {
CredentialItem[] goodCredentialItems = makeCredentialItems();
CredentialItem[] badCredentialItems = new CredentialItem[] {
goodCredentialItems[0],
goodCredentialItems[1],
new CredentialItem.YesNoType("OK?")
};
try {
provider.get(new URIish(AWS_REPO), badCredentialItems);
fail("Expected UnsupportedCredentialItem exception");
} catch (UnsupportedCredentialItem e) {
assertNotNull(e.getMessage());
}
}
@Test
public void testReturnsCredentials() throws URISyntaxException {
CredentialItem[] credentialItems = makeCredentialItems();
assertTrue(provider.get(new URIish(AWS_REPO), credentialItems));
String theUsername = ((CredentialItem.Username) credentialItems[0]).getValue();
char[] thePassword = ((CredentialItem.Password) credentialItems[1]).getValue();
assertEquals(USER, theUsername);
assertNotNull(thePassword);
// The password will always begin with a timestamp like
// 20161113T121314Z
assertTrue(thePassword.length > 16);
assertEquals('T', thePassword[8]);
assertEquals('Z', thePassword[15]);
}
private CredentialItem[] makeCredentialItems() {
CredentialItem[] credentialItems = new CredentialItem[2];
credentialItems[0] = new CredentialItem.Username();
credentialItems[1] = new CredentialItem.Password();
return credentialItems;
}
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright 2013-2015 the original author or authors.
*
* Licensed 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.springframework.cloud.config.server.credentials;
import static org.junit.Assert.*;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.junit.Before;
import org.junit.Test;
/**
* @author don laidlaw
*
*/
public class GitCredentialsProviderFactoryTests {
private static final String PASSWORD = "secret";
private static final String USER = "test";
private static final String FILE_REPO = "file:///home/user/repo";
private static final String GIT_REPO = "https://github.com/spring-cloud/spring-cloud-config-test";
private static final String AWS_REPO = "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/test";
private GitCredentialsProviderFactory factory;
@Before
public void init() {
factory = new GitCredentialsProviderFactory();
}
@Test
public void testCreateForFileNoUsernameIsNull() {
CredentialsProvider provider = factory.createFor(FILE_REPO, null, null);
assertNull(provider);
}
@Test
public void testCreateForFileWithUsername() {
CredentialsProvider provider = factory.createFor(FILE_REPO, USER, PASSWORD);
assertNotNull(provider);
assertTrue(provider instanceof UsernamePasswordCredentialsProvider);
}
@Test
public void testCreateForServerNoUsernameIsNull() {
CredentialsProvider provider = factory.createFor(GIT_REPO, null, null);
assertNull(provider);
}
@Test
public void testCreateForServerWithUsername() {
CredentialsProvider provider = factory.createFor(GIT_REPO, USER, PASSWORD);
assertNotNull(provider);
assertTrue(provider instanceof UsernamePasswordCredentialsProvider);
}
@Test
public void testCreateForAwsNoUsername() {
CredentialsProvider provider = factory.createFor(AWS_REPO, null, null);
assertNotNull(provider);
assertTrue(provider instanceof AwsCodeCommitCredentialProvider);
AwsCodeCommitCredentialProvider aws = (AwsCodeCommitCredentialProvider) provider;
assertNull(aws.getUsername());
assertNull(aws.getPassword());
}
@Test
public void testCreateForAwsWithUsername() {
CredentialsProvider provider = factory.createFor(AWS_REPO, USER, PASSWORD);
assertNotNull(provider);
assertTrue(provider instanceof AwsCodeCommitCredentialProvider);
AwsCodeCommitCredentialProvider aws = (AwsCodeCommitCredentialProvider) provider;
assertEquals(USER, aws.getUsername());
assertEquals(PASSWORD, aws.getPassword());
}
@Test
public void testCreateForAwsDisabled() {
factory.setAwsCodeCommitEnabled(false);
CredentialsProvider provider = factory.createFor(AWS_REPO, null, null);
assertNull(provider);
provider = factory.createFor(AWS_REPO, USER, PASSWORD);
assertNotNull(provider);
assertTrue(provider instanceof UsernamePasswordCredentialsProvider);
}
@Test
public void testIsAwsCodeCommitEnabled() {
assertTrue(factory.isAwsCodeCommitEnabled());
}
@Test
public void testSetAwsCodeCommitEnabled() {
assertTrue(factory.isAwsCodeCommitEnabled());
factory.setAwsCodeCommitEnabled(false);
assertFalse(factory.isAwsCodeCommitEnabled());
}
}