forked from Azure/autorest-clientruntime-for-java
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request Azure#144 from jianghaolu/clicreds
Add AzureCliCredentials
- Loading branch information
Showing
31 changed files
with
644 additions
and
247 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
155 changes: 155 additions & 0 deletions
155
...ent-authentication/src/main/java/com/microsoft/azure/credentials/AzureCliCredentials.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
/** | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for | ||
* license information. | ||
*/ | ||
|
||
package com.microsoft.azure.credentials; | ||
|
||
import com.fasterxml.jackson.core.type.TypeReference; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.microsoft.azure.AzureEnvironment; | ||
import com.microsoft.rest.serializer.JacksonAdapter; | ||
import okhttp3.OkHttpClient; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.nio.file.Paths; | ||
import java.text.SimpleDateFormat; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
import java.util.concurrent.locks.Lock; | ||
import java.util.concurrent.locks.ReentrantLock; | ||
|
||
/** | ||
* Token based credentials for use with a REST Service Client. | ||
*/ | ||
public final class AzureCliCredentials extends AzureTokenCredentials { | ||
private static final ObjectMapper MAPPER = new JacksonAdapter().serializer().setDateFormat(new SimpleDateFormat("yyyy-MM-dd hh:mm:ssssss")); | ||
/** A mapping from resource endpoint to its cached access token. */ | ||
private Map<String, AzureCliSubscription> subscriptions; | ||
private String defaultSubscriptionId; | ||
private File azureProfile; | ||
private File accessTokens; | ||
private Lock lock = new ReentrantLock(); | ||
|
||
private AzureCliCredentials() { | ||
super(null, null); | ||
subscriptions = new ConcurrentHashMap<>(); | ||
} | ||
|
||
private synchronized void loadAccessTokens() throws IOException { | ||
try { | ||
AzureCliSubscription.Wrapper wrapper = MAPPER.readValue(azureProfile, AzureCliSubscription.Wrapper.class); | ||
List<AzureCliToken> tokens = MAPPER.readValue(accessTokens, new TypeReference<List<AzureCliToken>>() { }); | ||
while (wrapper == null || tokens == null || tokens.isEmpty() || wrapper.subscriptions == null || wrapper.subscriptions.isEmpty()) { | ||
System.err.println("Please login in Azure CLI and press any key to continue after you've successfully logged in."); | ||
System.in.read(); | ||
wrapper = MAPPER.readValue(azureProfile, AzureCliSubscription.Wrapper.class); | ||
tokens = MAPPER.readValue(accessTokens, new TypeReference<List<AzureCliToken>>() { }); | ||
} | ||
for (AzureCliSubscription subscription : wrapper.subscriptions) { | ||
for (AzureCliToken token : tokens) { | ||
// Find match of user and tenant | ||
if (subscription.isServicePrincipal() == token.isServicePrincipal() | ||
&& subscription.userName().equalsIgnoreCase(token.user()) | ||
&& subscription.tenant().equalsIgnoreCase(token.tenant())) { | ||
subscriptions.put(subscription.id(), subscription.withToken(token)); | ||
if (subscription.isDefault()) { | ||
defaultSubscriptionId = subscription.id(); | ||
} | ||
} | ||
} | ||
} | ||
} catch (IOException e) { | ||
System.err.println(String.format("Cannot read files %s and %s. Are you logged in Azure CLI?", azureProfile.getAbsolutePath(), accessTokens.getAbsolutePath())); | ||
throw e; | ||
} | ||
} | ||
|
||
/** | ||
* Creates an instance of AzureCliCredentials with the default Azure CLI configuration. | ||
* | ||
* @return an instance of AzureCliCredentials | ||
* @throws IOException if the Azure CLI token files are not accessible | ||
*/ | ||
public static AzureCliCredentials create() throws IOException { | ||
return create( | ||
Paths.get(System.getProperty("user.home"), ".azure", "azureProfile.json").toFile(), | ||
Paths.get(System.getProperty("user.home"), ".azure", "accessTokens.json").toFile()); | ||
} | ||
|
||
/** | ||
* Creates an instance of AzureCliCredentials with custom locations of the token files. | ||
* | ||
* @param azureProfile the azureProfile.json file created by Azure CLI | ||
* @param accessTokens the accessTokens.json file created by Azure CLI | ||
* @return an instance of AzureCliCredentials | ||
* @throws IOException if the Azure CLI token files are not accessible | ||
*/ | ||
public static AzureCliCredentials create(File azureProfile, File accessTokens) throws IOException { | ||
AzureCliCredentials credentials = new AzureCliCredentials(); | ||
credentials.azureProfile = azureProfile; | ||
credentials.accessTokens = accessTokens; | ||
credentials.loadAccessTokens(); | ||
return credentials; | ||
} | ||
|
||
/** | ||
* @return the active directory application client id | ||
*/ | ||
public String clientId() { | ||
return subscriptions.get(defaultSubscriptionId).clientId(); | ||
} | ||
|
||
/** | ||
* @return the tenant or domain the containing the application | ||
*/ | ||
@Override | ||
public String domain() { | ||
return subscriptions.get(defaultSubscriptionId).tenant(); | ||
} | ||
|
||
/** | ||
* @return the Azure environment to authenticate with | ||
*/ | ||
public AzureEnvironment environment() { | ||
return subscriptions.get(defaultSubscriptionId).environment(); | ||
} | ||
|
||
/** | ||
* @return the default subscription ID logged in in Azure CLI | ||
*/ | ||
public String defaultSubscriptionId() { | ||
return defaultSubscriptionId; | ||
} | ||
|
||
/** | ||
* Set default subscription ID. | ||
* | ||
* @param subscriptionId the default subscription ID. | ||
* @return the credentials object itself. | ||
*/ | ||
public AzureCliCredentials withDefaultSubscriptionId(String subscriptionId) { | ||
this.defaultSubscriptionId = subscriptionId; | ||
return this; | ||
} | ||
|
||
@Override | ||
public synchronized String getToken(String resource) throws IOException { | ||
String token = subscriptions.get(defaultSubscriptionId).credentialInstance().getToken(resource); | ||
if (token == null) { | ||
System.err.println("Please login in Azure CLI and press any key to continue after you've successfully logged in."); | ||
System.in.read(); | ||
loadAccessTokens(); | ||
token = subscriptions.get(defaultSubscriptionId).credentialInstance().getToken(resource); | ||
} | ||
return token; | ||
} | ||
|
||
@Override | ||
public void applyCredentialsFilter(OkHttpClient.Builder clientBuilder) { | ||
clientBuilder.interceptors().add(new AzureTokenCredentialsInterceptor(this)); | ||
} | ||
} |
Oops, something went wrong.