MS Graph API - Adding 3rd party certificate for signing SAML tokens - azure-active-directory

I'm trying to add 3rd party certificates to my enterprise application in AzureAD using the MS Graph API. I found this post from 2 years ago Azure Graph API - Add a custom signing key - Invalid certificate: Key value is invalid certificate. The poster reported back that he/she has it working but when I try the same following the mentioned article and his/her workaround it still only generates a self signed certificate.
This is what I post at my service principal (as per step 4 in https://learn.microsoft.com/en-us/graph/application-saml-sso-configure-api#step-4-configure-a-signing-certificate): https://graph.microsoft.com/v1.0/servicePrincipals/
**
{
"keyCredentials": [
{ "type": "AsymmetricX509Cert",
"keyId": "e5cfed1e-1cb0-49bf-a743-b34f34048495",
"customKeyIdentifier": "Y6p0Dm1eBwzsa7P1xIObqsLUj6A=",
"usage": "Verify",
"key": "MIIFKjCCBB....bYRj6rEeEPyiFVd07mM4Ve"
},
{ "type": "X509CertAndPassword",
"customKeyIdentifier": "Y6p0Dm1eBwzsa7P1xIObqsLUj6A=",
"usage": "Sign",
"key": "MIIReQIBAzCCE.....xpGdpsqiNLA==",
"keyId": "fcd8d6d3-1dfe-4cab-a92e-b92167f362ab"
}
],
"passwordCredentials": [
{
"customKeyIdentifier": "Y6p0Dm1eBwzsa7P1xIObqsLUj6A=",
"keyId": "fcd8d6d3-1dfe-4cab-a92e-b92167f362ab",
"secretText": "password1"
}
],
"preferredTokenSigningKeyThumbprint": "28e2546eb43e8227944979729857d8c5c76d8727",
"preferredSingleSignOnMode": "saml",
"notificationEmailAddresses": [
"fake#test.com"
]
}
**
The response is that it generated a self signed MS cert:
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.selfSignedCertificate",
"customKeyIdentifier": "3clV2ULc6UX7yCKPBmeKWZ5n60k=",
"displayName": "CN=Microsoft Azure Federated SSO Certificate",
"endDateTime": "2025-08-10T10:37:37.6919735Z",
"key": "MIIC6DCCAdCgAwIBAgIIIkEYzJjHb4EwDQYJKoZIhvcNAQELBQAwNDEyMDAGA1UEAwwpTWljcm9zb2Z0IEF6dXJlIEZlZGVyYXRlZCBTU08gQ2VydGlmaWNhdGUwHhcNMjIwODEwMTAyNzM3WhcNMjUwODEwMTAzNzM3WjA0MTIwMAYDVQQDDClNaWNyb3NvZnQgQXp1cmUgRmVkZXJhdGVkIFNTTyBDZXJ0aWZpY2F0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJOVwMXWJV2RFl86Ko/5L3zgks7SIH67f/czzBJ7nEthRu5UfVaE7OPFH6Kaa7gRmLPAoIUtm9D6J/gtGIwcqXb4RN8CKjp4iOPb57yGTjeT0fNU+4wlFt0NyEjDWWBgATQTwuiUb6zUtsh+XW1IuCOjS1zYFlT6LP9JyC/uc8rJb+iYj0o3BsExWcIIC5LQ+0xPv2yN0PB2uwjkBhvK9FuLz38YjPEOEotNbPCx0pajVn1RWmqlSMwMVNLXvcHz+NKrHlQq0V0HBTlPFHy2d0ofLzAIqqrwuRqkE6S6rnAgjkl1rlizTAMvVLQBweouptfoV3pwG+0aU38uZG8Nf/8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAQo/AOuPQuP9alJzc2xul2EzBifSP1L6B+Zif8a76rLkADmS5eCG1AHtWXF3R6KA1y2Dq+H07uAaS8RVQpx1a91yO5uxJNdSBAUpEw4IM3VzeYALbqowdiTz5yVH2GD5TbjJq9+Rf3LXyPCumFSxWcHyUL/8iq3wyXLctKZWOku7LTI7vnO1omcoy/eKCuOxiAXIfOLNPlMBBR0x8mOcPlAx1bIswMGqXNEYD3I81c697I4t2XE++Gnk+z1q7tS4I6AyFUynCQ4okEf1YUChSV59sIAeLjRA4VAahZnHdMtIjbV7DCDscdAHZQRPZbFSg5FhFh5/Ww1YGf3qpCZuOUw==",
"keyId": "b764e6b1-985d-47a9-b703-824a94ed2b8b",
"startDateTime": "2022-08-10T10:27:37.6919735Z",
"thumbprint": "DDC955D942DCE945FBC8228F06678A599E67EB49",
"type": "AsymmetricX509Cert",
"usage": "Verify"
}
I've also tried patching the application itself as per: "Applications that don’t have any existing valid certificates (no certificates have been added yet, or all certificates have expired), won’t be able to use this service action. You can use the Update application operation to perform an update instead." (sourced from https://learn.microsoft.com/en-us/graph/api/application-addkey?view=graph-rest-1.0&tabs=http)
You can upload 3rd party SAML signing certs via the UI but we want to automate the onboarding and have minimal human intervention. Does anyone know if its possible to do this?
Cheers

Related

Authenticating to Sharepoint Online Site via React SPA in MS Teams personal Tab

When adding a Sharepoint Online site to a MS Teams static Tab referring to this Q&A helps greatly, but how would I go about when having a React single page application Tab and and a Sharepoint online Tab in the same application?
{
"entityId": "id1",
"name": "name1",
"contentUrl": "https://*********.sharepoint.com/_layouts/15/teamslogon.aspx?SPFX=true&dest=/SitePages/Home.aspx",
"scopes": [
"personal"
]
},
{
"entityId": "id2",
"name": "name2",
"contentUrl": "https://{{HOSTNAME}}/tab",
"scopes": [
"personal"
]
}],
As I need to set the defined source to the AAD Application needed for the React SPA I have trouble authenticating to and displaying the Sharepointsite in the MS Teams desktop application.
"webApplicationInfo": {
"id": "xxxxxx-xxxx-xxxx-xxxx-xxxxxxxx",
"resource": "api://subdomain.domain.com/xxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"},
Am I missing something obvious? Would I need to authenticate to Sharepoint trough the AAD App and if so, using which authentication method?
Your help is greatly appreciated!
#AdoTbo, Your webapplicationinfo look good, just make sure correct values are passed. You need to perform AD authentication only. SharePoint authentication also internally uses AD authentication.
You can exchange the AAD token with SharePoint which is getting generated for app resource. Please check the detailed documentation.

Got 'Insufficient privileges to complete the operation.'. MS Graph Api

I have an issue with the Microsoft Graph API.
I have registered a new app in the Azure portal
Added Application.ReadWrite.All and Application.ReadWrite.OwnedBy application permissions
Click on the admin consent button
empty
After that, I'm trying to get an access token by
POST https://login.microsoftonline.com/12fb9222-8b6e-4006-a483-a87fa44621c3/oauth2/v2.0/token
client_id=dc07d452-9ce1-4b0f-a1a6-4fb5b230a4bb
scope=https://graph.microsoft.com/.default
grant_type=client_credentials
client_secret={client_secret}
And I'm getting the token.
Token looks like that:
{
"aud": "https://graph.microsoft.com",
"iss": "https://sts.windows.net/12fb9222-8b6e-4006-a483-a87fa44621c3/",
"iat": 1570007742,
"nbf": 1570007742,
"exp": 1570011642,
"aio": "42VgYHi/n737QYBx8DrOTW5Ft0skAQ==",
"app_displayname": "testapp",
"appid": "dc07d452-9ce1-4b0f-a1a6-4fb5b230a4bb",
"appidacr": "1",
"idp": "https://sts.windows.net/12fb9222-8b6e-4006-a483-a87fa44621c3/",
"oid": "24d9cd08-efaf-497b-b023-920cc208400a",
"roles": [
"Application.ReadWrite.OwnedBy",
"Application.ReadWrite.All",
],
"sub": "24d9cd08-efaf-497b-b023-920cc208400a",
"tid": "12fb9222-8b6e-4006-a483-a87fa44621c3",
"uti": "f38JDx5iw0Kkp16mnZIqAA",
"ver": "1.0",
"xms_tcdt": 1569224302
}
After that, I'm executing
GET https://graph.microsoft.com/beta/applications/bb4c22ea-632e-45d8-ad0f-2ba39cf399c1
And I'm getting app properties.
And finally I want to update my app properties and I'm trying execute
PATCH https://graph.microsoft.com/beta/applications/bb4c22ea-632e-45d8-ad0f-2ba39cf399c1
{
"displayName": "displayName"
}
And I'm getting:
{
"error": {
"code": "Authorization_RequestDenied",
"message": "Insufficient privileges to complete the operation.",
"innerError": {
"request-id": "1565bb72-8392-4ca7-bb20-02b40f5603bd",
"date": "2019-10-02T09:23:57"
}
}
}
I'm confused. I have permissions for the API update application, but I got the error, please help.
This seems like a bug, I tried with client credentials and granted Application.ReadWrite.All and Application.ReadWrite.OwnedBy permissions. I encountered the same error as yours.
Then I tried with Delegated permission with a user login, it worked. You can follow this article or just call the api with Microsoft Graph explorer.
Note:
APIs under the /beta version in Microsoft Graph are subject to change.
Use of these APIs in production applications is not supported.

How to use ARM templates to deploy a roleAssignment for an App Registration Service Principal?

In my current project I'm working with pre-created App Registration Service Principals in Azure AD. I'm using an ARM template to create a StorageV2 account plus some blob containers, then create a roleAssignment giving Storage Blob Contributor rights to one of the Service Principals. The relevant section of the ARM template is at the end of this post.
What I've found is that if I take the ObjectId of a regular AD user, such as myself or my colleague, and set that as PrincipalId, the script runs correctly. However, I can't get this to work with a Service Principal.
If I use the Service Principal's ObjectId, then I get the following error:
Deployment failed. Correlation ID: 40e0c146-165a-47c0-b022-ac04781d8194. {
"error": {
"code": "PrincipalTypeNotSupported",
"message": "Principals of type Application cannot validly be used in role assignments."
}
}
Having spotted some suggestions for Azure Powershell users that I should use Application (Client) Id instead, I tried that, but get the following error (Guids redacted):
Deployment failed. Correlation ID: 5c725a51-230a-4d85-bb61-b2f4cdf849ff. {
"error": {
"code": "PrincipalNotFound",
"message": "Principal 9f****30 does not exist in the directory db****75."
}
}
So the ObjectId it can find but not use, and the ClientId it can't find.
I have found that if I use Azure Powershell and use the New-AzureRmRoleAssignment command, I can reproduce the PrincipalTypeNotSupported error by providing the Service Principal's ObjectId to the -ObjectId switch. However, that command also has a -ServicePrincipalName switch as an alternative, and if I give that the Service Principal's ClientId, it works!
Is there any equivalent of -ServicePrincipalName for the ARM templates, and if not, is there any other way to achieve this? I can use Azure Powershell as a workaround, but it's messier than I'd like.
If this is a feature gap, where's the best place to report it?
Relevant section of ARM template follows:
"resources": [
{
"name": "[variables('storageAccountName')]",
"type": "Microsoft.Storage/storageAccounts",
"location": "[resourceGroup().location]",
"apiVersion": "2018-07-01",
"sku": {
"name": "[parameters('storageAccountSku')]"
},
"dependsOn": [],
"tags": {
"displayName": "Storage Account"
},
"kind": "StorageV2",
"properties": {
"accessTier": "Hot",
"supportsHttpsTrafficOnly": true,
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": [],
"ipRules": [],
"defaultAction": "Deny"
}
},
"resources": [
{
"type": "blobServices/containers",
"name": "[concat('default/', variables('myBlobContainerName'))]",
"apiVersion": "2018-07-01",
"dependsOn": [
"[variables('storageAccountName')]"
],
"resources": [
{
"type": "Microsoft.Authorization/roleAssignments",
"name": "[variables('myRoleAssignmentGuid')]",
"apiVersion": "2018-07-01",
"properties": {
"roleDefinitionId": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/ba92f5b4-2d11-453d-a403-e96b0029c9fe')]",
"principalId": "[variables('myPrincipalId')]"
},
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'), '/blobServices/default/containers/', variables('myBlobContainerName'))]"
]
}
]
}
]
}
]
Finally solved this one thanks in part to the pointers from #4c74356b41.
When an Application Registration object is created, an identically named object is also created under Enterprise Applications. This has the same ApplicationId, but a different ObjectId, and it's the ObjectId of this Enterprise Application object that our ARM script needs.
You can find this object in the portal by going to the Application Registration entry, then clicking on the link after Managed application in...
Screenshot of App Registration with Link
Once you're on the corresponding Enterprise Application object, you can get the ObjectId from Properties, and use this the value for principalId in the ARM template.
At the time of writing, the Microsoft Documentation is a bit vague on this, with the terms Application and Service Principal seemingly overloaded. This article says that when you register an application you get an Application object and a Service Principal object, but doesn't use the phrase Enterprise Application once, or refer to App Registration objects per se, so it's unclear which is which.
I'm assuming Application == Application Registration and Service Principal == Enterprise Application. This SO post would seem to suggest this is the case, as would the solution above.

Identity Server 4 access token with user info

So I have began practicing and using Identity Server 4, my goal is to have an authentication and authorization server for all the applications within my organization. I got to the point where I can log in correctly to my identity server from a third application and get my access_token and it works nicely.
The second step is to get my userinfo inside my access_token but when I decode it I get this:
{
"nbf": 1505250392,
"exp": 1505253992,
"iss": "http://localhost:5000",
"aud": [
"http://localhost:5000/resources",
"SecretAPIEndpoints"
],
"client_id": "SecretClient",
"sub": "ebf3fcad-6ab3-4bcd-88ce-0c5794ebdffa",
"auth_time": 1505250391,
"idp": "local",
"scope": [
"openid",
"SecretAPIEndpoints"
],
"amr": [
"pwd"
]
}
So if I use this token I can make my endpoints work correctly but I want to get it one step further and get my SPA to show my user first name and last name and also their email and roles.
I haven't found documentation or examples to make this happen, so any bit of help would be greatly appreciated.
If you want to consume identity data in JS-based client app, ask for an id_token in addition to an access token.
https://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth

Role/Group based Authorization using ADAL.js and ASP.NET Web API

What we are planning to achieve is a role-based security for a Front end Angular-2 and back-end ASP.NET Web API application. We are doing the authentication process with the help of ADAL.js and storing the token in the local storage. We have also implemented the approach shown here i.e. to call the Graphi API and get the user groups to stuff them into Claims.
My question is : Is there anyway, we can add role claims from server to the bearerToken which is residing in the local storage. Or is there any better way to approach this issue.
The code sample mentioned assign the role based on the group. If you have the Azure AD basic version, it support to assign the role to the users/groups directly.
My question is : Is there anyway, we can add role claims from server to the bearerToken which is residing in the local storage. Or is there any better way to approach this issue.
Yes, it is possible. To issue the role claims we need to assign the users to assign the roles to users or group first. Then when the user acquire the token, the Azure AD would issue the relative role claims in the token.
You can refer the code sample for using the role claim from here.
And you may also be interest in groups claim developing.
ok i was struggling with this for a while and i have figured it out i believe.
First,
In Azure AD, set up your WebApi app as application type to be Web App / API.
go to Manifest file and add your roles like
[
{
"allowedMemberTypes": [
"User"
],
"displayName": "Reviewer",
"id": "0238c2bb-9857-4d07-b760-a47ec621d57a",
"isEnabled": true,
"description": "Reviewer only have the ability to view tasks and their statuses.",
"value": "reviewer"
},
{
"allowedMemberTypes": [
"User"
],
"displayName": "Approver",
"id": "000018cb-19e3-4f89-bf99-5d7acf30773b",
"isEnabled": true,
"description": "Approvers have the ability to change the status of tasks.",
"value": "approver"
}
]
Then create the the Client app as Application type to be Native app and add required permissions to the service you added above.
In the SPA Angular app add something like this
var endPoints = {
// "https://localhost:44386/" is the API URL
// "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" is the Service Application ID
"https://localhost:44386/": "xxxxxxxxxxxxxxxxxxxxxxxxxx"
};
adalAuthenticationServiceProvider.init({
instance: "https://login.microsoftonline.com/",
// tenant is your tenant name (something like below)
tenant: "{NAME}.onmicrosoft.com",
// this is the Native app application ID (ClientID) you registered
clientId: "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy",
extraQueryParameter: "nux=1",
endpoints: endPoints
}, $httpProvider);
}
]);
Then, in your startup.cs you need to set up the Service App like the following:
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
TokenValidationParameters = new TokenValidationParameters
{
/* "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" is the Service Application ID. (Same as you registered in the client app above)*/
ValidAudience = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
RoleClaimType = "roles"
},
/*enant is your tenant name (same as you registered in client app above)*/
Tenant = "{NAME}.onmicrosoft.com"
});
Finally you need to go to Azure active directory => Enterprise application => all applications => select your webAPI service => Users and groups => then assign users to the roles.
When this is all done when you log through your client app to authenticate and call the webapi, adal.js and ada-angular.js will put the proper bearer token that contains roles
Good to learn this approach.
Ted, thanks for sharing your solution !
For those who are not familiar with operating Azure AD manifest file. The following is a good resource.
https://thinkthencode.wordpress.com/2016/04/24/azure-ad-using-app-roles-for-authorization/
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"displayName": "Reviewer",
"id": "0238c2bb-9857-4d07-b760-a47ec621d57a",
"isEnabled": true,
"description": "Reviewer only have the ability to view tasks and their statuses.",
"value": "reviewer"
},
{
"allowedMemberTypes": [
"User"
],
"displayName": "Approver",
"id": "000018cb-19e3-4f89-bf99-5d7acf30773b",
"isEnabled": true,
"description": "Approvers have the ability to change the status of tasks.",
"value": "approver"
}
]

Resources