How to deal with two IDPs having the same entity ID - azure-active-directory

I need to declare 2 IDPs in spring-security-saml having the same entity id.
My webapp uses spring-security-saml.
This webapp is accessible by 2 differents URLs behind a reverse proxy.
The first URL is public, the second URL is filtered.
So, I declared 2 SP (one for each URL).
Everything was working properly with a single IDP (ADFS or Gsuite).
I also run the application properly with 2 SPs and 2 IDPs with an affinity SP1/IDP1 and SP2/IDP2 when IDP1 and IDP2 had a different entity ID.
Unfortunately by wanting to use Azure Active Directory, each SAML application in Azure results in its own IDP metadata with its own certificate, but with the same entity id.
So I need to declare 2 IDPs in spring-security-saml having the same entity id.
Reading the code shows that it is not intended to work like this (the entity id is used as key).
Do you have an idea to work around this problem?
Should Azure provide a unique entity id ?

I know it is too old but just found it but you can not use the same Entity ID per tenant for 2 different apps, so it makes sense that the apps have a different certificate even if they have same Entity ID because both apps are in different tenants

How it worked for me!!
As Spring saml works only for unique IDP entityIds. So to make it unique for 2 different IDP having same entity Ids, I prexied one of it with alias as i know what is that alias is for.
So now I have to hack entityID at certain places of initialization, validation during metadata loading AND in SAML response verification.
For metadata(one that has prefixed entity Id) loading to be successful especially one with signed metadata..
Created new child class MySAMLSignatureProfileValidator that overrides
SAMLSignatureProfileValidator.validateReferenceURI.
To use this I need to create another custom class SamlSignatureValidationFilter that extends MYSamlSignatureValidationFilter and initialise MySAMLSignatureProfileValidator in their constructor.
Use this SamlSignatureValidationFilter when we add metadata to metadata manager like this..
metadataProvider.setMetadataFilter(new MYSamlSignatureValidationFilter(metadata.getTrustEngine(metadataProvider)));
And now add another custom class MYSAMLCachingMetadataManager to override initializeProviderFilters and remove the logic to setMetadataFilter as its already set as in above code.
Use MYSAMLCachingMetadataManager in your config for MetadataManager.
This should take care of saml metadata loading.
Then coming to SAML Response that has the issuer as the original entityId, we need to add prefixed alias to the context here so that it verifies with our prefixed_entityId stored in metadatamanager entity list.
In this case I added MySamlHttpPostDecoder that overrides HttpPostDecoder.extractResponseInfo to add alias to messageIssuer.
And, MySamlWebSSOProfileConsumerImpl to overirde WebSSOProfileConsumerImpl.verifyIssuer to set issuer.getValue with alias. so later verification with stored entitId will match.
Use this MySamlWebSSOProfileConsumerImpl and MySamlHttpPostDecoder in your config. To use MySamlHttpPostDecoder I need to add new class MySamlHTTPPostBinding(ParserPool parserPool, VelocityEngine velocityEngine, MessageDecoder decoder) that extends HTTPPostBinding and pass MySamlHttpPostDecoder for decoder.
Hope it works for you too!!!

Related

How to add Single sign-on support for bots to existing application?

Currently we have an application in production that allows for Single sign-on in tabs, we followed https://learn.microsoft.com/en-us/microsoftteams/platform/tabs/how-to/authentication/auth-aad-sso and this works well.
For this to work an Application ID URI is set, like so: api://www.domainusedintab.com/378271d1-b8e4-4f01-a9bb-e724dbec43c8, where 378271d1-b8e4-4f01-a9bb-e724dbec43c8 is some application ID.
We now want to add Single sign-on support for bots, like described in https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/authentication/auth-aad-sso-bots. To make this work a change is needed to the Application ID URI, api://botid-5d417275-b104-462e-9998-2b2b0ec4244f, where 5d417275-b104-462e-9998-2b2b0ec4244f is the ID of the bot service.
The problem is that it's not clear on how to combines these two into a single Application ID URI, based on the previous documentation pages it seems it's one way or the other.
We tried to just tack on /botid-5d417275-b104-462e-9998-2b2b0ec4244f after our current Application ID URI, to make api://www.domainusedintab.com/378271d1-b8e4-4f01-a9bb-e724dbec43c8/botid-5d417275-b104-462e-9998-2b2b0ec4244f. This seems to work fine... But it also seems like a bit of a hack that might break at any time.
Are there any resources on how to properly solve this?
We can add the existing bots to the existing application to work on SSO. We need to add the web applcation info in the manifest to view the changes in the application. For more information please check Single sign-on (SSO) support for bots
As it turns out, it is possible to provide multiple Application ID URIs for an App registration. This is not available through the Expose an API interface, you need to change it directly in the manifest. The identifierUris field holds the Application ID URIs — the current one from the Expose an API interface should be the only item here.

Clarification on Identityserver 4 protecting API scopes with ApiResources

I don't really understand the protecting API using APIResource and APIScopes
I have an angular client application which is calling a .Net APIs lets say API1, Api2 , How can I define the values in APIResource.
I am going through the Identity server4 (version 4.0.0) database table after migration. I found the tables as below
ApiResources
ApiResourceScopes
ApiResourceClaims
ApiResourceProperties
ApiResourceSecrets
ApiScopes
ApiScopeClaims
ApiScopeProperties
My understanding was either we can use 1-5 tables for API setups or we can use 6-8 tables. I tried with tables 1-5. Added values in ApiResources ,ApiResourceScopes & ApiResourceClaims but getting below error
[18:03:53 Debug] IdentityServer4.EntityFramework.Stores.ResourceStore
Found ["TestAPI.Read"] scopes in database
Values in Tables
what is the use of ApiResourceClaims table? is this returning user claims with access token?
How do I access this scope from the client?
Is there any other tables, do I need to add data?
First I recommend that you read my answer here
what is the use of ApiResourceClaims table? is this returning user claims with access token?
It contains a list of user claims that will be included in the access token. Meaning, the names of the claims that it will then take from the user database.
How do I access this scope from the client?
You need to tie an ApiScope. You ask for a ApiScope that then will include one or more ApiResources.
ApiResources represents the individual API's in your system. So, you have one ApiResource per API. You use the ApiResource name and secret to let individual API authenticate against IdentityServer and login to for example get details about the access token (Token introspection)
I think this picture I have below shows the relations between the various parts:
The client asks for a ApiSCope and that will then create an access token that will give access to one or multiple ApiResources. Each ApiResource might using the userclaims ask for additional user information that you want to have present in the Access token. Perhaps for the authorization step in the API. To determine if the user is really allowed in or not.
To complement this answer, I write a blog post that goes into more detail about this topic:
IdentityServer – IdentityResource vs. ApiResource vs. ApiScope

Best practise for populating access token with external claims

We have implemented IdSrv4 on top of AspNetCore Identity and we use ADFS as external IdP. From ADFS we wan´t to get the users AD-groups, upn and som other claims. The claims will be used both inside our IdSrv4 implementation, but will also be sent to our API-resources as part of the access token.
The current situation in our IdSrv4 implementation:
ADFS has been configured so that it emits the claims that we want and in our IdSrv4 implementation those claims are received as expected in the "ExternalLoginCallback" method of the AccountController.
IProfileService has been implemented in order to fill the "IssuedClaims" list with claims.
BUT, I haven't managed to build the connection between those to steps. What is the preferred way to preserve the claims received in "ExternalLoginCallback" and put them into the generated access_token in the IProfileService class?
Right now I have managed to get it working by saving the token using the method "UpdateExternalAuthenticationTokensAsync", which will save the token in the database. Then in the profile service I fetch the token and read the claims into the emitted token.
But this doesn't feel right and while searching for the proper way I´ve seen examples use the class IdentityServerUser that has "AdditionalClaims" property, but I can't find a way to plug that type into the event flow.
Also, when configuring the external IdP you have these "ClaimActions" that can be mapped, but I don't understand what they are.
Finally, I assume that the database tables "IdentityClaims" and "ClientClaims" with corresponding entities should be used for this purpose but I can´t figure out how. Or should they be saved in the "AspNetUserClaims" table to save the actual claim type/values and not only claim mappings?
So basically, there must be a best practice for this scenario that seem to avoid me and I would be greatful if someone could share it.
The main issue in my problem was that the problems I first encountered with persisting the Claims in the AspNetIdentity-Db led me to a wild goose chase.
Returning to this after a week or so made me give this another shot. Turns out that the DI injected "_userManager" wasn't "connected" to the current DI injected "_signInManager". If someone has an explanation for this, please share!
What did work was to use the "_signInManager.UserManager" to update Claims on the user. This properly stores the Claims in the "AspNetUserClaims" table, and can then be retrieved in the profile service.
UPDATE 1:
Of course there was a logical answer to that as well. A user manager is created by default even if you don't call "AddUserManager" on your identity setup during startup. BUT, in my case I have extended the IdentityUser class and now by doing it like this it all works as excpected (where "UserIdentity" is my derived class):
.AddIdentity<TUserIdentity, TUserIdentityRole>(options =>
{
options.User.RequireUniqueEmail = true;
})
.AddEntityFrameworkStores<TIdentityDbContext>()
.AddSignInManager<SignInManager<UserIdentity>>()
.AddUserManager<UserManager<UserIdentity>>()
.AddDefaultTokenProviders();

Is it possible to update/delete User by externalId

We are trying to develop a SCIM enabled Provisioning system for provisioning data from an Enterprise Cloud Subscriber(ECS) to Salesforce(Cloud Service Provider-CSP). We are following SCIM 1.1 standard.
What are we able to do:
We are able to perform CRUD operations on User object using Salesforce auto-generated userId field
Exact Problem:
We are not able to update/delete User object using externalId provided by ECS.
Tried something as below... But it is not working, Unknown_Exception is thrown...
XXX/my.salesforce.com/services/scim/v1/Users/701984?fields=externalId
Please note that it is not possible to store Salesforce userId in ECS's database due to some compliance reasons. So we have to completely depend upon externalId only.
Possible Workaround:
Step1: Read the userId based on externalId from Salesforce
Step2: Update the User object using the salesforce UserId obtained in Step1.
But this two step process would definitely degrade the performance.
Is there any way to update/delete the User by externalId
Could you please guide us on this..
Thanks so much....
I realize this is old thread but wanted to note that you CAN update Users from REST using an external ID. The endpoint in above question is incorrect. Following is how it should be set, send as a PATCH request:
[instance]/services/data/v37.0/sobjects/user/[external_id__c]/[external id value]
Instance = your instance i.e. https://test.salesforce.com/
external_id__c = API name of your custom external Id field on User
external id value = whatever the value of the user's external Id
NOTES:
Salesforce responds with an HTTP 204 status code with No Content in the body, this isn't usual for patch requests, but it is 'success' response
The external id on user has to be a custom field, make sure it is set
as UNIQUE
Ensure the profile/permission set of the user that is making the call
has the Manage Users permission & has access to the external id field
It is pretty common pattern for other applications, too, to search first and then perform on update on the returned object. Your workaround seems fine to me. What performance problem are you concerned about? Are you concerned about Salesforce not being able to process more requests or are you concerned about the higher response time in your application because you need to make multiple requests? Have you actually measured how much an extra call costs?

Use URL part to create multi tenant AppEngine application

I'm trying different ways of implement multi tenant AppEngine web RESTful interface.
One of them is to use part of the URL as the tenant name.
The problem is that I'm using Jersey as JAX-RS implementation for RESTful interface and I would like a url such as /tenant1/res1 to first be parsed by something that will take the /tenant1 part, set the namespace to tenant1 and then pass the rest of the URL to Jerseys' servlet for regular handling.
The something maybe either ServletFilter or Servlet or something I can't think of.
How can I implement such thing?
What are the possible problems of such implementation?
Thank you,
Ido.
I do exactly that but using Restlet. The namespace uniquely identifies the customer that a user belongs to.
The first URL fragment contains the namespace. I verify the namespace in a RESTLET authenticator (basically a filter) and when the authenticated user does not belong to the given namespace/customer I refuse to proceed.
I use the primary key of the customer as the namespace. This has the added advantage that a valid namespace/customer can be easily (mem-)cached, and I refuse any calls containing invalid namespaces.
Very happy with this setup and no problems encountered.

Resources