Can't seem to find this anywhere in the docs; if I am authenticated with BasicAWSCredentials, e.g. AccessKeyId and SecretKey, is it possible to get the AWS Account ID?
Update
AWS has just silently addressed this long standing gap by introducing the dedicated STS API action GetCallerIdentity, which returns details about the IAM identity whose credentials are used to call the API, including the AWS Account ID - there are a few sample responses, e.g.:
<GetCallerIdentityResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
<GetCallerIdentityResult>
<Arn>arn:aws:iam::123456789012:user/Alice</Arn>
<UserId>AKIAI44QH8DHBEXAMPLE</UserId>
<Account>123456789012</Account>
</GetCallerIdentityResult>
<ResponseMetadata>
<RequestId>01234567-89ab-cdef-0123-456789abcdef</RequestId>
</ResponseMetadata>
</GetCallerIdentityResponse>
You can use the AWS Command Line Interface to obtain just the account ID, here's an example:
$ aws sts get-caller-identity --output text --query Account
121371349383
Initial Answer
This is at least indirectly possible via AWS Identity and Access Management (IAM) by means of the GetUser action (available via getUser() in the AWS SDK for Java):
Retrieves information about the specified user, including the user's
path, GUID, and ARN.
If you do not specify a user name, IAM determines the user name
implicitly based on the AWS Access Key ID signing the request.
The returned User data type (Class User) contains an Arn element (getArn()), which is the Amazon Resource Name (ARN) specifying the user. This is further detaild in Identifiers for IAM Entities, specifically in section ARNs, which describes the format of the User Resource Type:
arn:aws:iam::{account_ID}:user/{path/to/user/UserName}
Example: arn:aws:iam::123456789012:user/division_abc/subdivision_xyz/Bob
This is an old question, but for the poor souls out there -
The answer based on ARN is the most correct answer that we found. There's also an OwnerId field when calling DescribeInstances, but there may be no instances ..
However the reality is a bit more complex. Sometimes the IAM user does not have the permission to issue getUser(), and then he gets AmazonServiceException with
getErrorCode() = "AccessDenied"
In this case, the ARN is a part of the AWS error message:
User: arn:aws:iam::123456789012:user/division_abc/subdivision_xyz/Bob is not authorized to perform:
iam:GetUser on resource: arn:aws:iam::123456789012:user/division_abc/subdivision_xyz/Bob
So here the matters are even worse: we need to parse a free text error message and then extract the account number:
try {
... iam.getUser(); ...
} catch (AmazonServiceException e) {
if (e.getErrorCode().compareTo("AccessDenied") == 0) {
String arn = null;
String msg = e.getMessage();
// User: arn:aws:iam::123456789012:user/division_abc/subdivision_xyz/Bob is not authorized to perform: iam:GetUser on resource: arn:aws:iam::123456789012:user/division_abc/subdivision_xyz/Bob
int arnIdx = msg.indexOf("arn:aws");
if (arnIdx != -1) {
int arnSpace = msg.indexOf(" ", arnIdx);
arn = msg.substring(arnIdx, arnSpace);
}
System.out.println("ARN: " + arn);
}
If you have the AWS CLI tools, you can:
aws iam get-user | awk '/arn:aws:/{print $2}'
Here's the code to get the newer STS getCallerIdentity stuff working (in Java):
private String getAccountIDUsingAccessKey(String accessKey, String secretKey) {
AWSSecurityTokenService stsService = AWSSecurityTokenServiceClientBuilder.standard().withCredentials(
new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey, secretKey))).build();
GetCallerIdentityResult callerIdentity = stsService.getCallerIdentity(new GetCallerIdentityRequest());
return callerIdentity.getAccount();
}
Props to #SteffenOpel for giving the clues needed, of course.
With the latest API there's a direct way of finding the user ID:
BasicAWSCredentials basicAWSCredentials = new BasicAWSCredentials("your access key", "your secret key");
AmazonIdentityManagementClient iamClient = new AmazonIdentityManagementClient(basicAWSCredentials);
String userId = iamClient.getUser().getUser().getUserId();
Adding this here, because it's the top SO result for "find aws account number", and because it's bad practice to use keys instead of IAM Roles for deployed apps anyway...
If you're running from an AWS instance that has an IAM Role on it, you can do curl -s http://169.254.169.254/latest/meta-data/iam/info and get the ARN of the instance's role from the InstanceProfileArn key of the results, without having to worry about trying to parse an exception message or granting IAM permissions to an instance that doesn't need them.
Then, you just have to parse the ARN for the account number.
I made a funny discovery - if you call GetRole with a non-existent RoleName, the error message you get back contains the ARN of the calling account, so just parse out the account number from that. This is nice because it works in all cases that I can think of, even if the caller does not have permissions to call GetRole.
Here's the error message I get:
User: arn:aws:sts::669916120315:assumed-role/CloudMail_Server/i-31dd19cd is not authorized to perform: iam:GetRole on resource: role _no_such_role_
The '669916120315' portion of the error message is the AWS Account ID.
While I don't consider this an ideal scenario, it does get the job done. This uses the AWSSDK 3.0.
public string GetUserId()
{
AmazonIdentityManagementServiceClient c =
new AmazonIdentityManagementServiceClient();
GetUserRequest request = new GetUserRequest();
GetUserResponse response = c.GetUser(request);
//parse it from the ARN
//should be similar to "arn:aws:iam::111111111111:user/username"
string[] arnParts = response.User.Arn.Split(new char[] { ':' });
return arnParts[4];
}
Using AWS Java SDK v2:
public String getAccountId(AwsCredentialsProvider awsAuth, Region awsRegion) {
StsClient stsClient = getClient(awsAuth, awsRegion);
GetCallerIdentityRequest request = GetCallerIdentityRequest
.builder()
.build();
GetCallerIdentityResponse response = stsClient.getCallerIdentity(request);
return response.account();
}
public StsClient getClient(AwsCredentialsProvider awsAuth, Region awsRegion) {
return StsClient
.builder()
.credentialsProvider(awsAuth)
.region(awsRegion)
.build();
}
The owner of the default security group is the "account ID"
ElasticTranscoder ListPresets returns a data structure that includes ARNs that include the AWS account id.
Unlike many other popular suggestions, this aws-cli command works for basic credentials, IAM user, IAM roles, instance roles, and cross-account role assumption:
aws elastictranscoder list-presets --query 'Presets[0].Arn' |
cut -d: -f5
Of course, you will need permission to make the ListPresets API call, but that's true of any answer.
Some answers provide a way to retrieve the AWS Account ID from an IAM User. Those solutions will generate a runtime exception if you use the credentials of an IAM Role.
In this case, you can do this:
// you can get it with #Import(SnsConfiguration::class) for instance
#Autowired
private AWSCredentialsProvider credentialsProvider;
private String resolveAmazonAccountId() {
AmazonIdentityManagement imClient = AmazonIdentityManagementClientBuilder.standard()
.withCredentials(credentialsProvider)
.build();
String roleArn = imClient.getRole(new GetRoleRequest().withRoleName("role name")).getRole().getArn();
// https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns
// arn:partition:service:region:account:resource
return roleArn.split(":")[4];
}
Related
ClientSecretCredential clientSecret = new ClientSecretCredentialBuilder()
.clientId("********-****-****-****-************").tenantId(
"********-****-****-****-************")
.clientSecret("*****~***************************~******").build();
BlobServiceClient blobServiceClient = new BlobServiceClientBuilder()
.credential(clientSecret)
.endpoint("https://sambhutestsa.blob.core.windows.net/")
.buildClient();
BlobContainerClient blobContainerClient = blobServiceClient.getBlobContainerClient("testcontainer");
System.out.printf("Identifier for the snapshot is %s%n", blobContainerClient.getBlobClient("2824891.jpg").downloadToFile("C:\\Users\\ss255248\\2824891.jpg");
but getting this error can someone please help here.
Exception in thread "main" com.azure.storage.blob.models.BlobStorageException: If you are using a StorageSharedKeyCredential, and the server returned an error message that says 'Signature did not match', you can compare the string to sign with the one generated by the SDK. To log the string to sign, pass in the context key value pair 'Azure-Storage-Log-String-To-Sign': true to the appropriate method call.
If you are using a SAS token, and the server returned an error message that says 'Signature did not match', you can compare the string to sign with the one generated by the SDK. To log the string to sign, pass in the context key value pair 'Azure-Storage-Log-String-To-Sign': true to the appropriate generateSas method call.
Please remember to disable 'Azure-Storage-Log-String-To-Sign' before going to production as this string can potentially contain PII.
Status code 403, "<?xml version="1.0" encoding="utf-8"?><Error><Code>AuthorizationPermissionMismatch</Code><Message>This request is not authorized to perform this operation using this permission.
RequestId:d813ea5f-d01e-004d-7b0f-656de3000000
Time:2022-05-11T08:13:50.0902556Z</Message></Error>
To resolve the error, please try the following:
Make sure whether you have below roles assigned to your security principal:
Storage Blob Data Contributor
Storage Blob Data Owner
If not, make sure to assign it like below:
Go to Azure Portal ->Identify the required scope (Subscription/Resource group) -> Access Control (IAM) -> Add Role assignment
Check whether your application has below API permissions:
For more information, please refer this MsDoc:
Otherwise, try setting the time zone to UTC-0 .
Try adding comp=list&restype=container to your SAS URL as a workaround.
Make use of the snippet suggested in this SO thread.
For more in detail, please refer below link:
Azure App Service rejected with 403 error by Storage Account - Stack Overflow
[Solved] Azure Shared Access Signature - Signature did not match - Local Coder
I am using authentication of users in Java 8 against Keycloak, with the Keycloak adapter API for Java.
In this case, the class KeycloakBuilder (keycloak-admin-client-6.0.0.jar) builds a Keycloak instance to perform authentication operations.
how can I request an offline token rather than a normal Bearer token using this API?
Have not found parameter or way to request it. I need tokens with 1 month expiration time, which cannot get unless change the "SSO Session Max" field, but I donĀ“t want this to affect other Clients or users in the same Realm / client.
I am not sure if there are any specialties with the Keycloak Java adapter but I already implemented this with other clients. On the Authorization server side, you need to add a role offline_access to the users, which are allowed to request an offline session (this can be done explicitly or as a default role mapping). On the client side, you have to add another scope offline_access to the auth request. This can also be done by default (see default scopes). Please refer to the official Keycloak documentation about Offline Sessions for further details.
I post a possible solution using keycloak-authz-client library instead.
As stated by #Philipp , it is also necessary that the user you log in with has the role offline_access.
public String login(String username, String password) {
String authServerUrl = "http://localhost:18080/auth"; // Your keycloak auth entpoint
String realm = "realm"; // Realm
String clientId = "client"; // Client
Map<String, Object> clientCredentials = new LinkedHashMap<String, Object>();
clientCredentials.put("secret", "clientSecret"); // Client secret (Access Type: Confidential)
Configuration configuration = new Configuration(
authServerUrl,
realm,
clientId,
clientCredentials,
null
);
AuthzClient authzClient = AuthzClient.create(configuration);
AuthorizationRequest request = new AuthorizationRequest();
request.setScope("offline_access");
AuthorizationResponse response = authzClient.authorization(username, password).authorize(request);
return response.getRefreshToken(); // response.getToken() returns the bearer token
}
I tried to get graph api token from postman UI and was able to get planner data.
How to achieve same in java spring
I am not able to get access token for Microsoft graph api using java spring. I am able to get access token using postman.
I need to access planner API from one of the web application. As per Microsoft documentation I configured a app in azure active directory and got client key, secret key etc.
I also configured required permission to get groups and users.
Very first time I used below from POSTMAN
https://login.microsoftonline.com//oauth2/token with below data
client_id : <client_id from configured app>
client_secret : <client secret from configured app>
grant_type : client_credentials
resource : https://graph.microsoft.com
I got token, and I was able to get groups from https://graph.microsoft.com/v1.0/groups/
But same token was not valid for getting plans of group.
With lot of digging, I came to know that token accessed with client_credentials is not applicable to get data from planner API. So, next I used below details to get access token from UI of postman.
Grant Type : authorization_code
Callback URL : https://www.getpostman.com/oauth2/callback
Auth URL : https://login.microsoftonline.com/<tenant_id>/oauth2/authorize?resource=https://graph.microsoft.com
Access Token URL : https://login.microsoftonline.com/<tenant_id>/oauth2/v2.0/token
client_id : <client_id from configured app>
client_secret : <client secret from configured app>
I got the Microsoft login screen, and after successful login, I got token.
I could call planner API using this access token.
Now my question is how can I get this same token using java spring.
Also, my web app will be having background service running in scheduler calling graph API daily.
I do not want manual intervention here, but as told earlier, graph API will ask to login.
How to achieve above requirement.
private String getAuth() {
ConfidentialClientApplication app = null;
IClientCredential credential = ClientCredentialFactory.create(Appsecret);
try {
app = ConfidentialClientApplication.builder(MicrsoftAppId, credential).authority("https://login.microsoftonline.com/"+tenantId+"/").build();
}catch(MalformedURLException e) {
System.out.println(e.getMessage());
}
ClientCredentialParameters parameters = ClientCredentialParameters.builder(Collections.singleton("https://graph.microsoft.com/.default")).build();
CompletableFuture<IAuthenticationResult> future = app.acquireToken(parameters);
try {
IAuthenticationResult result = future.get();
return result.accessToken();
}catch(ExecutionException e){
System.out.println(e.getMessage());
}catch(InterruptedException e) {
System.out.println(e.getMessage());
}
return null;
}
Here you go! This code is made for application permission (so not delegated). It only requires your client Id and secret to operate. You will need the microsoft graph jar for it to work (and the many jars supporting it).
I am running the official SDK Junit codes, and it works fine. But when I change the account info into mine, exception occur.
Debug says it return http status of 400 when posting to endpoint "/oauth/token",
I have save my private key generated in docusign admin page, into "docusign_private_key.txt"
ApiClient apiClient = new ApiClient (BaseUrl);
//String currentDir = System.getProperty("user.dir");
try
{
// IMPORTANT NOTE:
// the first time you ask for a JWT access token, you should grant access by making the following call
// get DocuSign OAuth authorization url:
//String oauthLoginUrl = apiClient.getJWTUri(IntegratorKey, RedirectURI, OAuthBaseUrl);
// open DocuSign OAuth authorization url in the browser, login and grant access
//Desktop.getDesktop().browse(URI.create(oauthLoginUrl));
// END OF NOTE
byte[] privateKeyBytes = null;
try
{
privateKeyBytes = Files.readAllBytes (Paths.get (privateKeyFullPath) );
}
catch (IOException ioExcp)
{
Assert.assertEquals (null, ioExcp);
}
if (privateKeyBytes == null)
{
return;
}
java.util.List<String> scopes = new ArrayList<String>();
scopes.add (OAuth.Scope_SIGNATURE);
scopes.add (OAuth.Scope_IMPERSONATION);
OAuth.OAuthToken oAuthToken = apiClient.requestJWTUserToken (IntegratorKey, UserId, scopes, privateKeyBytes, 3600);
}
Problem solved.
The SDK JUnit code defines a parameter called "UserId", it should be filled by "API Username" , not "API Account ID" from Admin page.
Thanks for all you kind people.
Per the note in the comments, you need to grant one-time user consent per key for your app to use it, have you done that? If you have Organizations enabled (which is an enterprise feature) then you can do it across the entire account, otherwise you'll need to grant consent manually on a one-by-one (ie user by user) basis.
If granting consent manually (which is what most integrations do) you need to configure your Integrator Key with the Redirect URI you will be passing through code, then redirect your user to the following URL in a web browser (the "-d" part of the URL means this would be for the demo environment):
https://account-d.docusign.com/oauth/auth?
response_type=YOUR_RESPONSE_TYPE
&scope=open_id
&client_id=YOUR_INTEGRATOR_KEY
&state=YOUR_CUSTOM_STATE
&redirect_uri=YOUR_REDIRECT_URI
&admin_consent_scope=YOUR_REQUESTED_SCOPES
If done correctly the user will be taken to the standard DocuSign login page. After successful login they can explicitly grant consent to your app and will then be re-directed back to your app through the Redirect URI param you configured.
Here is a guide that explains how to obtain consent using either method:
https://developers.docusign.com/esign-rest-api/guides/authentication/obtaining-consent
In particular, when using DefaultAWSCredentialsProviderChain in a test environment, it can be surprising which set of credentials the AWS SDK picks up. To this end, it would be helpful to find out, which user or role was used to make a request.
I tried with the following code:
AmazonIdentityManagement amazonIdentityManagement = AmazonIdentityManagementClient
.builder()
.withRegion(REGION)
.build();
User user = amazonIdentityManagement.getUser().getUser();
log.info("AWS self-check successful with user {}: {}", user.getUserName(), user.getArn());
This should work if the user has permissions to query IAM. On my test system I get:
com.amazonaws.services.identitymanagement.model.AmazonIdentityManagementException:
User: arn:aws:iam::999:user/test.developer is not authorized to perform: iam:GetUser on resource: arn:aws:iam::999:user/test.developer
(Service: AmazonIdentityManagement; Status Code: 403; Error Code: AccessDenied; Request ID: xxx)
This gets close to what I want wrapped in an exception. Can I directly get the arn String?
Yes, you can get the ARN as long as the user has the permission to perform: iam:GetUser.
I'm testing similar thing so i can confirm that.