I am using MSAL to validate a user against Microsoft Azure AD and am getting a valid token back.
The MSAL library is handing me back a User object which contains a property called userIdentifier.
This is a string, not a GUID.
The documentation says to use a field called oid to uniquely identify users across the Microsoft Identity platform. I have this property available under User.idToken.oid.
This value is a GUID as the documentation says.
My question is, what is this User.userIdentifier and should I be using this? I need to know what to store on the database side to tie this local user to an Azure AD user.
For clarity's sake it is advised to use the accountIdentifier property as it will always be populated, even in the edge cases where oid might not be available:
const accountIdentifier: string = idToken.objectId || idToken.subject;
More info on GitHub.
Looking at the source code (https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-core/src/Account.ts), there is no userIdentifier, but there is an accountIdentifier.
Could be yours is an older version, in which case this might not be correct for that.
// create accountIdentifier
const accountIdentifier: string = idToken.objectId || idToken.subject;
It is either the oid or sub claim, whichever has a value.
If you want the oid, you should get it from the idTokenClaims property on Account.
Related
Our organization stores signing certificates in Active Directory. We are using anonymous bind to search for them at a base DN (e.g. OU=MY ORG,dc=mydc,dc=org). I have been trying to use the Spring LdapTemplate to look them up, but no matter what method I use, I get the cryptic InterruptedNamingException.
Assuming a cert subject of cn=mycert.myorg.com
My code looks like this
LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl(String.format(LDAP_URL_FORMAT, ldapCertStoreParameters.getServerName(),
ldapCertStoreParameters.getPort()));
contextSource.setBase(ldapCertStoreParameters.getBaseDn());
contextSource.setAnonymousReadOnly(true);
contextSource.afterPropertiesSet();
LdapTemplate ldapTemplate = new LdapTemplate(contextSource);
ldapTemplate.setIgnorePartialResultException(true);
ldapTemplate.afterPropertiesSet();
X500Principal principal = x509CertSelector.getSubject();
Object obj = ldapTemplate.lookup(new LdapName(principal.getName()));
The X500 principal's name is the whole dn. cn=mycert.myorg.com,OU=MY ORG,dc=mydc,dc=org
I have also tried the search using just the cn.
We have verified that the DN exists on the server using Apache Directory Studio.
• I would suggest you to please remove the call altogether or set the ‘userSearchBase’ either to an empty String (“”) as per the given example in the below community thread: -
Configure Spring security for Ldap connection
As in the ‘AbstractContextSource’, set the base suffix from which all operations should origin. If a base suffix is set, you will not have to (and, indeed, must not) specify the full distinguished names in any operations performed. Since you specified the full DN for the userDN/filter, you must not specify the base.
AD servers are apparently unable to handle referrals automatically, which causes a ‘PartialResultException’ to be thrown whenever a referral is encountered in a search. To avoid this, set the ‘ignorePartialResultException’ property to true. There is currently no way of manually handling these referrals in the form of ‘ReferralException’, i.e., either you get the exception (and your results are lost) or all referrals are ignored (if the server is unable to handle them properly). Neither is there any simple way to get notified that a ‘PartialResultException’ has been ignored.
For more details regarding the LDAP template search for Active Directory stored certificates, kindly refer to the link below: -
https://docs.spring.io/spring-ldap/docs/current/apidocs/org/springframework/ldap/core/LdapTemplate.html
• Also, please try to refer to the below documentation for configuration of Springboot LDAP template configuration through certificates stored in Active Directory: -
https://www.baeldung.com/x-509-authentication-in-spring-security
I need to know the client's grant type (or OAuth Flow type) in my API protected by IdentitySrever4, but not sure how to do that. I am assuming that I need to add the grant type to the access token. Can someone help me by pointing me to instructions/documentations or sample code?
UPDATE
Under standard IdentityServer4 EF model, my SQL Server data store has a ClientGrantTypes table and a ClientClaims table (see screenshot below). I am assuming that I need to create a ClientClaims record that ties into ClientGrantTypes. If it is SQL, you can just join the tables on ClientID, but how do you implement it here to get the Grant Type into access token?
It would be easier to find the answer if you explained the purpose for the requirement. From my experience one common task is to distinguish authorization_code and client_credentials flow use for the same client, but that's easy: the second one does not contain user information (sub and sid claims).
Also don't forget about restricted auth flow combinations in Identityserver (for instance you can't allow both implicit and authorization_code flow for the same client), so one client is usually bound to the only user interactive flow.
Finally, the auth flow is generally not about API. It's only about interaction among IdP and Client. API usually use scopes as general information about clients, so... when you have two clients -- one with implicit grant and the other with authorization_code, you can distinguish which one is in use by setting different scopes.
Isn't that enough?
A check for a particular grant type could be performed in Identityserver the following way:
public class ExtendedClaimsService : DefaultClaimsService{
public override async Task<IEnumerable<Claim>> GetAccessTokenClaimsAsync(
ClaimsPrincipal subject,
ResourceValidationResult resourceResult,
ValidatedRequest request)
{
var outputClaims = (await base.GetAccessTokenClaimsAsync(subject, resourceResult, request)).ToList();
//if (request.Secret.Type == "NoSecret") //this is more or less the same
if ((request as ValidatedTokenRequest)?.GrantType != "client_credentials")
{
//filter out server-side-only scopes here
//or add any custom claim you like
}
return outputClaims;
}
}
Registration: services.AddTransient<IClaimsService, ExtendedClaimsService>(); after services.AddIdentityServer() in your Startup
One option is to have different client definitions for the different flows and then use a ClientClaim to indicate what type of client it is:
To set the client claims in the client definition just set it like:
ClientClaimsPrefix="",
AlwaysSendClientClaims=true,
Claims = new List<ClientClaim>()
{
new ClientClaim("role","admin"),
new ClientClaim("name","joe"),
new ClientClaim("admin","yes"),
new ClientClaim("employmentid","employee"),
new ClientClaim("employeetype","yes"),
new ClientClaim("creditlimit","100000")
}
We have an external vendor that requires us to include a bearer token in the http request header when we communicate with the API. This token shouldn't be left in the code unencrypted so where is the best place to store it? The Named Credential type doesn't seem to support storing a simple token and the Custom Setting option seems overly complicated and unnecessary. This is a single token string that will be used for every API call regardless of which user. I have searched high and low on google and haven't found an obvious solution that works.
There are some options but they're limited for your code as end user. A determined developer/sysadmin will learn the value eventually.
If you'd build a managed package you could use a protected custom setting (managed package's code could see it but not the client code, even sysadmins)
Check some of these:
https://developer.salesforce.com/page/Secure_Coding_Storing_Secrets
https://salesforce.stackexchange.com/questions/226110/what-is-the-best-way-of-storing-username-and-password-in-salesforce
https://salesforce.stackexchange.com/questions/478/using-transient-keyword-to-store-password-in-hierarchy-custom-setting
https://salesforce.stackexchange.com/questions/55008/is-encrypting-passwords-in-protected-custom-settings-a-security-requirement
You could make a custom setting with 2 text fields, 1 with encryption key and 1 with encrypted value in it. Look at Crypto class.
Blob exampleIv = Blob.valueOf('Example of IV123');
Blob key = Crypto.generateAesKey(128);
Blob data = Blob.valueOf('Data to be encrypted');
Blob encrypted = Crypto.encrypt('AES128', key, exampleIv, data);
Blob decrypted = Crypto.decrypt('AES128', key, exampleIv, encrypted);
String decryptedString = decrypted.toString();
System.assertEquals('Data to be encrypted', decryptedString);
Your initialisation vector could be org's id or something else that's easy to access and unlikely to change (I don't know if your vendor's API has test and prod endpoints but it's an added bonus that after sandbox refresh this will fail to decrypt OK until you change the custom setting... you wouldn't want to send test messages to production API), you'd generate key once & store it in setting.
Is it possible to somehow extend IdentityServer4 to run custom authentication logic? I have the requirement to validate credentials against a couple of existing custom identity systems and struggle to find an extension point to do so (they use custom protocols).
All of these existing systems have the concept on an API key which the client side knows. The IdentityServer job should now be to validate this API key and also extract some existing claims from the system.
I imagine to do something like this:
POST /connect/token
custom_provider_name=my_custom_provider_1&
custom_provider_api_key=secret_api_key
Then I do my logic to call my_custom_provider_1, validate the API key, get the claims and pass them back to the IdentityServer flow to do the rest.
Is this possible?
I'm assuming you have control over the clients, and the requests they make, so you can make the appropriate calls to your Identity Server.
It is possible to use custom authentication logic, after all that is what the ResourceOwnerPassword flow is all about: the client passes information to the Connect/token endpoint and you write code to decide what that information means and decide whether this is enough to authenticate that client. You'll definitely be going off the beaten track to do what you want though, because convention says that the information the client passes is a username and a password.
In your Startup.ConfigureServices you will need to add your own implementation of an IResourceOwnerPasswordValidator, kind of like this:
services.AddTransient<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();
Then in the ValidateAsync method of that class you can do whatever logic you like to decide whether to set the context.Result to a successful GrantValidationResult, or a failed one. One thing that can help you in that method, is that the ResourceOwnerPasswordValidationContext has access to the raw request. So any custom fields you add into the original call to the connect/token endpoint will be available to you. This is where you could add your custom fields (provider name, api key etc).
Good luck!
EDIT: The above could work, but is really abusing a standard grant/flow. Much better is the approach found by the OP to use the IExtensionGrantValidator interface to roll your own grant type and authentication logic. For example:
Call from client to identity server:
POST /connect/token
grant_type=my_crap_grant&
scope=my_desired_scope&
rhubarb=true&
custard=true&
music=ska
Register your extension grant with DI:
services.AddTransient<IExtensionGrantValidator, MyCrapGrantValidator>();
And implement your grant validator:
public class MyCrapGrantValidator : IExtensionGrantValidator
{
// your custom grant needs a name, used in the Post to /connect/token
public string GrantType => "my_crap_grant";
public async Task ValidateAsync(ExtensionGrantValidationContext context)
{
// Get the values for the data you expect to be used for your custom grant type
var rhubarb = context.Request.Raw.Get("rhubarb");
var custard = context.Request.Raw.Get("custard");
var music = context.Request.Raw.Get("music");
if (string.IsNullOrWhiteSpace(rhubarb)||string.IsNullOrWhiteSpace(custard)||string.IsNullOrWhiteSpace(music)
{
// this request doesn't have the data we'd expect for our grant type
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
return Task.FromResult(false);
}
// Do your logic to work out, based on the data provided, whether
// this request is valid or not
if (bool.Parse(rhubarb) && bool.Parse(custard) && music=="ska")
{
// This grant gives access to any client that simply makes a
// request with rhubarb and custard both true, and has music
// equal to ska. You should do better and involve databases and
// other technical things
var sub = "ThisIsNotGoodSub";
context.Result = new GrantValidationResult(sub,"my_crap_grant");
Task.FromResult(0);
}
// Otherwise they're unauthorised
context.Result = new GrantValidationResult(TokenRequestErrors.UnauthorizedClient);
return Task.FromResult(false);
}
}
We're using LDAP to authenticate users against a large Active Directory setup. We want to extract the list of all groups from Active Directory so that we can mirror them in a local database, and map users' AD groups to local groups.
However when we run the ldap query to get a list of all groups, Active Directory limits the maximum results for our search.
What is the best strategy to get this information given the limitations on query result size? Can we use some form of query paging?
Thanks in advance!
Active-Directory support pagging control. You must refer to Microsoft official article : Searching the Directory ans especialy Search Size and Page Size
A simple paged results query can be used to do that. The key would be to ensure that the requested page size does not exceed whatever the maximum results size is for your Active Directory instance.
The ADO wrappers for ADSI, for example, automatically page results, an example of which can be found here, though obviously that may or may not work for you depending on your technology stack.
If you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
You can use a PrincipalSearcher and a "query-by-example" principal to do your searching:
// create your domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// define a "query-by-example" principal - here, we search for any GroupPrincipal
GroupPrincipal qbeGroup = new GroupPrincipal(ctx);
// create your principal searcher passing in the QBE principal
PrincipalSearcher srch = new PrincipalSearcher(qbeGroup);
// to get around the 1'000 or so object limit - you need to "go deep" and
// set the page size on the underlying DirectorySearcher to e.g. 500
(searcher.GetUnderlyingSearcher() as DirectorySearcher).PageSize = 500;
// find all matches
foreach(var found in srch.FindAll())
{
// do whatever here - "found" is of type "Principal" - it could be user, group, computer.....
}
You can specify any of the properties on the GroupPrincipal and use those as "query-by-example" for your PrincipalSearcher.