DefaultAzureCredential: Graph access forbidden with VisualStudio Code Credential - visual-studio-code

I'm trying to read user properties from ms graph inside an Azure function.
For authentication I used the DefaultAzureCredential class from Azure.Identity.
Access with Shared Token Cache Credential locally and Managed Identity Credential in Azure is no prob!
I wanted to use the Visual Studio Code Credential, but I get an "Authorization_RequestDenied! Insufficient privileges to complete the operation" error message when I call the graph API.
The problem seems to be the access token I received with the VS Code Credential. The user account is the same one I used with the Shared Token Cache Credential.
Any ideas? Thank you.
Code:
DefaultAzureCredentialOptions options = new DefaultAzureCredentialOptions();
options.VisualStudioCodeTenantId = Environment.GetEnvironmentVariable("Debug_VisualStudioCodeTenantId");
var credential = new DefaultAzureCredential(options);
token = credential.GetToken(
new Azure.Core.TokenRequestContext(
new[] { "https://graph.microsoft.com/.default" }));
accessToken = token.Token;
var graphServiceClient = new GraphServiceClient(
new DelegateAuthenticationProvider((requestMessage) =>
{
requestMessage
.Headers
.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
return Task.CompletedTask;
}));
var users = await graphServiceClient.Users.Request().GetAsync(); // throw the forbidden exception
Exception:
"Code: Authorization_RequestDenied\r\nMessage: Insufficient privileges to complete the operation.\r\nInner error:\r\n\tAdditionalData:\r\n\tdate: 2021-04-20T08:02:23\r\n\trequest-id: ...\r\n\tclient-request-id: ...\r\nClientRequestId: ...\r\n"

After inspecting the token returned by VS Code, it seems to be missing a required delegated permission/scope.
The docs say one of these is required to list users:
User.ReadBasic.All, User.Read.All, User.ReadWrite.All, Directory.Read.All, Directory.ReadWrite.All, Directory.AccessAsUser.All
Since the service principal that VS Code is using does not require any of these, it won't work.
After trying to explicitly get the token with the required scope, it doesn't seem to work either.
So the VS Code credential currently just doesn't seem to work for this purpose.
You'll need a different credential or perhaps use the client secret/certificate credential with your own app registration.

Related

JWT Auth with Servicestack Ormlite - Generated Bearer token too large to use (>4096)

I'm migrating my ServiceStack Ormite MVC application to use the JWTAuthProvider for stateless auth. I have this working by authenticating as normal, and setting the returned BearerToken and RefreshToken on a successful auth:
using (var authService = HostContext.ResolveService<AuthenticateService>(ServiceStackRequest))
{
var response = await authService.PostAsync(new Authenticate
{
provider = CredentialsAuthProvider.Name,
UserName = model.UserName,
Password = model.Password,
RememberMe = true,
});
var authResponse = response.GetDto() as AuthenticateResponse;
Response.Cookies.Append("ss-tok", authResponse.BearerToken, new CookieOptions() {...});
Response.Cookies.Append("ss-reftok", authResponse.RefreshToken, new CookieOptions() {...});
}
This appears to work for some users and not for others. The problem seems to be that user accounts with a lot of permissions end up with much larger BearerToken values, some over 4096, so these cannot be set for the ss-tok cookie.
The JWT Auth provider docs provide references to the CreatePayloadFilter and the PopulateSessionFilter, however these are only used when creating a session from a token, not the other way around. I want to filter out items (the permissions in particular) when serializing to a token.
Ideally the permissions would be excluded if there are too many (or always be excluded if that's not possible) and would be lazy-loaded when accessed. This may be possible with a custom AuthUserSession inheriting from the base AuthUserSession that Lazy-loads the Permissions, but I don't know how I could do this without the JWT Provider loading the permissions to serialise too.

Websphere Commerce Custom REST service for Login using social sign in not generating valid WC Tokens and CTXMGMT table not getting updated

In the current website, social login is implemented using the mapping in struts and it will call the custom controller command "XYZThirdPartyLoginCmdImpl" which will authenticate the details passed and it will call the out of the box "LogonCmd" for login.
For creating a REST service for the above functinality, created a custom REST handler " XYZThirdPartyLoginHandler" and from there called the existing command "XYZThirdPartyLoginCmdImpl" using the method executeControllerCommandWithContext. Once the response is generated, WCToken and WCTrustedToken is generated by the below code.
ActivityToken token = getActivityToken();
String identitySignature = token.getSignature();
String identityId = token.getActivityGUID().getGUID().toString();
Map<String, Object> identityTokenInfo = new HashMap();
identityTokenInfo.put(MemberFacadeConstants.EC_USERID, new String[] { userId.toString() } );
identityTokenInfo.put(MemberFacadeConstants.ACTIVITY_TOKEN_ID, new String[] { identityId } );
identityTokenInfo.put(MemberFacadeConstants.ACTIVITY_TOKEN_SIGNATURE, new String[] { identitySignature } );
Map<String, String> commerceTokens = CommerceTokenHelper.generateCommerceTokens(identityTokenInfo);
String wcToken = commerceTokens.get(CommerceTokenHelper.WC_TOKEN);
String wcTrustedToken = commerceTokens.get(CommerceTokenHelper.WC_TRUSTED_TOKEN);
The tokens generated using this is not valid. If we try to invoke any other rest service using this token it shows invalid user session error. "XYZThirdPartyLoginCmdImpl" authentication is success as the userId returned is correct. After executing this the user context is not getting created in CTXMGMT table.
Please guide on how to generate the valid tokens in REST flow in this use case.
If you are on v9, you might want to investigate the oauth_validate REST call (/wcs/resources/store//loginidentity/oauth_validate). See the KC article for more information: [https://www.ibm.com/support/knowledgecenter/SSZLC2_9.0.0/com.ibm.commerce.integration.doc/tasks/tcv_sociallogin.htm][1]. This calls some different commands (OAuthTokenValidationCmdImpl and OpenUserRegisterCmd) than what you might be using, but it allows you to pass in a 3rd party token, and it generates the right tokens.

Get access token on Microsoft federated accounts

I'm trying to get access token for Power BI API. Our account is a federated account.
I've been trying this but it keeps giving me an error saying Incorrect username or password. To use the resource owner password credentials grant flow to get the access token for Azure AD, I make a call to http request diectly using the HttpClient
HttpClient clie = new HttpClient();
string tokenEndpoint = "https://login.microsoftonline.com/{tenant}/oauth2/token";
var body = "resource=https://analysis.windows.net/powerbi/api&client_id={client_id}&grant_type=password&username={username}&password={password}";
var stringContent = new StringContent(body, Encoding.UTF8, "application/x-www-form-urlencoded");
string result = clie.PostAsync(tokenEndpoint, stringContent).ContinueWith((response) =>
{
return response.Result.Content.ReadAsStringAsync().Result;
}).Result;
This will work for non federated accounts. How can I implement the same for federated accounts?
The easier would be to leverage MSAL.NET (or ADAL.NET) which does a lot to achieve that. See https://aka.ms/msal-net-up
scopes = new string[]{ "https://analysis.windows.net/powerbi/api/Dashboard.Read.All"}
result = await app.AcquireTokenByUsernamePasswordAsync(scopes, "joe#contoso.com",
securePassword);
Even better if you know that your machine is domain joined or AAD joined, you can use Integrated Windows Authentication: https://aka.ms/msal-net-iwa
result = await app.AcquireTokenByIntegratedWindowsAuthAsync(scopes);
Note that, I recommend using MSAL.NET (instead of ADAM.NET), because with MSAL/NET/the Azure AD v2.0 endpoint, PowerBI offers a better control of the permission scopes:
See the API permissions tab in an app registration in https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredAppsPreview

List Storage Accounts only listing a few classic storage accounts

List Storage Accounts https://management.core.windows.net//services/storageservices
says that it lists the storage accounts that are available in the specified subscription and the get storage account keys work only for these storage accounts that are returned as part of this call.
But the response is giving me only few storage accounts which are classic, how do i get the other storage accounts?
But the response is giving me only few storage accounts which are
classic, how do i get the other storage accounts?
By "other" storage accounts, I guess you're meaning "Azure Resource Manager (ARM)" storage accounts. There's a different API to get ARM storage accounts that make use of Azure AD based authentication.
To learn more about ARM API to list storage accounts, please see this link: https://learn.microsoft.com/en-us/rest/api/storagerp/storageaccounts#StorageAccounts_List.
To learn more about how to authenticate/authorize ARM API calls, please see this link: https://learn.microsoft.com/en-us/rest/api/
I agree with Gaurav Mantri, if you’d like to list ARM storage accounts under a specified subscription, please use this API:
GET https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Storage/storageAccounts?api-version=2016-12-01
And the following code sample works fine on my side, please refer to it.
string tenantId = "{tenantId}";
string clientId = "{clientId}";
string clientSecret = "{secret}";
string subscriptionid = "{subscriptionid}";
string authContextURL = "https://login.windows.net/" + tenantId;
var authenticationContext = new AuthenticationContext(authContextURL);
var credential = new ClientCredential(clientId, clientSecret);
var result = await authenticationContext.AcquireTokenAsync(resource: "https://management.azure.com/", clientCredential: credential);
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the JWT token");
}
string token = result.AccessToken;
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(string.Format("https://management.azure.com/subscriptions/{0}/providers/Microsoft.Storage/storageAccounts?api-version=2016-12-01", subscriptionid));
request.Method = "GET";
request.Headers["Authorization"] = "Bearer " + token;
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)request.GetResponse();
//extract data from response
}
catch (WebException ex)
{
//ex.Message;
}
Besides, this article explained how to create AD application and service principal that can access resources, please refer to it.
Thanks for your response,by other storage accounts I meant the storage accounts under the classic storage accounts itself which were not getting listed.
Instead of using
https://management.core.windows.net//services/storageservices
I used the REST API's
for the new storage accounts
/management.azure.com/subscriptions/id/providers/Microsoft.Storage/storageAccounts?api-version=2016-12-01
for classic:
/management.azure.com/subscriptions//providers/Microsoft.ClassicStorage/storageAccounts?api-version=
and to get keys
/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Storage/storageAccounts/{accountName}/listKeys?api-version=2016-12-01
/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ClassicStorage/storageAccounts/{accountName}/listKeys?api-version=2016-11-01

rest api unauthorized Azure Data Catalog

I am using Azure Data Catalog of my organization. I am not creator/administrator/owner of the Catalog but I have access to register/delete catalogs from the web interface.
I want to use rest API for Azure Data Catalog. Is it possible with my level of permission?
I have followed all the steps from https://msdn.microsoft.com/en-us/library/mt428033.aspx and written the following piece of code:
class Program
{
static void Main(string[] args)
{
string url = "https://api.azuredatacatalog.com/catalogs/DefaultCatalog/search/search?searchTerms=My_Server&count=10&startPage=1&api-version=2016-03-30";
HttpWebRequest request = System.Net.WebRequest.Create(url) as System.Net.HttpWebRequest;
Console.WriteLine(AccessToken().CreateAuthorizationHeader());
try
{
WebResponse response = request.GetResponse();
Console.WriteLine(response.ContentLength);
}
catch (Exception e)
{
Console.WriteLine(e);
}
Console.ReadKey();
}
static AuthenticationResult AccessToken()
{
string resourceUri = "https://datacatalog.azure.com";
string clientId = "my-client-id";
string redirectUri = "my-redirect-uri";
string authorityUri = "https://login.windows.net/common/oauth2/authorize";
AuthenticationContext authContext = new AuthenticationContext(authorityUri);
return authContext.AcquireToken(resourceUri, clientId, new Uri(redirectUri), PromptBehavior.RefreshSession);
}
}
and when I try to run the search from API, I get the following error:
System.Net.WebException: The remote server returned an error: (401)
Unauthorized. at System.Net.HttpWebRequest.GetResponse() at
HRBIADCAPI.Program.Main(String[] args) in
c:\users\naghimir\documents\visual studio
2015\Projects\HRBIADCAPI\HRBIADCAPI\Program.cs:line 32
Now I think the problem is that I have not given access to the client program created to read/write data catalog (that I did in Azure Data Factory) but that step is not there in the documentation either.
Do I need to be the owner or can I request permission from the owner to use Azure Data Catalog API?
Based on the description, you were using the OAuth 2.0 code grant flow to grant the app to delegate the user to manipulate the Azure Data Catalog.
To ensure the request works well, we need to grant the scope to the app like figure below:
And since the app only delegate the users’ permission, please ensure that user have the sufficient permission to operate the resource manfully.