I playing with webapi and trying to setup app configuration for proper signature validation in
WindowsAzureActiveDirectoryBearerAuthenticationOptions
I have noticed MetadataAddress field is not used in several examples online and in AAD auth samples: https://github.com/AzureADSamples/NativeClient-WebAPI-MultiTenant-WindowsStore/blob/master/TodoListServiceMT/App_Start/Startup.Auth.cs
When I launch the app I noticed there is a request to https://login.windows.net/common/federationmetadata/2007-06/federationmetadata.xml on app launch even though the field is not set. Is this the default value to MetadataAddress?
How does the signature validation work even though the sts address is
different in token?
How is the validation handled in case of custom sts service?
The tenant parameter passed in the option is enough for the middleware to determine the location of the metadata document of the corresponding Azure AD tenant. In the case of multitenant applications, as you observed that value is common. In the multitenant sample you can see that there is custom logic that takes over the verification of the issuer (what you called the "sts address" - that's more of an identifier). As you can see in the file that you linked, the options turn off the issuer validation via the switch ValidateIssuer = false. If you take a look at https://github.com/AzureADSamples/NativeClient-WebAPI-MultiTenant-WindowsStore/blob/master/TodoListServiceMT/AuthorizationFilters/MTAuthorizeAttribute.cs, you'll see that it executes logic meant to compare the issuer in the incoming token against a list of trusted issuer. Your own application might have different business logic for establishing whether the issuer of the incoming token should be trusted.
Related
I'm requesting the following scopes (URL encoded):
offline_access user.read https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send
The authorization process with OAuth 2.0 using the new Microsoft Graph API seems to work fine, but when using the access token to connect to IMAP over XOAuth2, I'm getting a NO AUTHENTICATE, which indicates the token is invalid.
It turns out this is not an issue with the user but rather with Microsoft's Graph API. Although it is not documented, you are currently not allowed to request a token with a scope that falls under two tenants, or it will choose one and fail silently.
In this case, User.Read falls under Microsoft Graph tenancy. Technically speaking, if your user is an organizational Outlook/Office365 user, they likely don't actually have Microsoft Graph installed and the correct scope would be https://outlook.office.com/User.Read. However the Outlook profile endpoint has been deprecated and would be unadvisable to use (you also have no way of knowing whether or not your user has MS Graph tenancy). It seems to resolve this, the user.read permission can be requested without specifying the Microsoft Graph URL.
This is essentially what you are doing above, but can be misleading as you are not actually requesting the general User.Read permission that can then be resolved to the Outlook tenant. What is actually happening is that User.Read permission is being mapped to some default tenant, and so your scopes actually contain multiple tenants (both the default tenant and Outlook).
Since this is not allowed, it fails silently and defaults to the default tenant. With most of their APIs this still works, but specifically with IMAP/SMTP you cannot request a larger scope/multi-tenant key or it will not validate over XOAuth2. You will note that the access tokens returned for IMAP/SMTP alone are always much smaller than the access tokens for other scopes.
To remedy this, you will need to request two access tokens. Firstly, you should use your authorization code to request a key within the following scope:
offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send
Following this, you need to request an access token for the profile. However, as of October 2020, you are no longer allowed to use a single authorization code for multiple access token grants. So you will need to login the user once more -- the canonical way of doing this is to simply navigate them back to the auth URL, leaving the login_hint field empty. This will vary depending on how you are constructing your URL, but here is an example in JS:
url = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize?'
url += `client_id=${clientId}`
url += '&response_type=code'
url += '&redirect_uri=${redirectURI}'
url += '&response_mode=query'
url += '&login_hint='
url += '&scope=offline_access%20User.Read%20https%3A%2F%2Foutlook.office.com%2FIMAP.AccessAsUser.All%20https%3A%2F%2Foutlook.office.com%2FSMTP.Send'
url += '&state=12345
Note that your authorization code must request the full scope (including both User.Read and IMAP scopes like IMAP.AccessAsUser.All, for both access token requests. Specifying a smaller scope will not guarantee that the profile you read will necessarily correspond to the Outlook account.
After receiving this second authorization code (it won't ask the user to login manually again, just load a bit and automatically resolve a second code) you can request a new access token with the following scope:
user.read
You can include any other Graph API scopes above, but specifying something under Outlook and especially under IMAP will mix up your scopes. The response scope will still contain EAS access and Outlook scopes, but with the addition of the user.read permission.
You should use this second token to access the profile and refresh it separately from the first token (which should only be used for IMAP/SMTP).
I 'm trying to create a secure spring rest api using pre-authentication security for siteminder.
I 've tried a solution where I 'm getting SM_USER and when I tested it in postman by adding new header SM_USER with random value it seems to work fine.
If you don't provide header I'm getting an error org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException: SM_USER header not found in request which is valid.
But how can I be sure that this is secure? if someone knows the URL of my rest api could call this without problem. Should I check something else in spring or only siteminder offers user authentication?
The front-end SiteMinder web agent is the guaranty that the session is valid - you must make sure via server/network configuration that your application cannot be accessed directly without first passing through the SiteMinder web agent.
Also, SiteMinder asserts multiple headers. SM_USER should not be used alone because it can be asserted by the web agent in some circumstances when the user does not actually have a valid session. Instead, you should first look for the existence (non-blank) of SM_SERVERSESSIONID, which only exists if the session is valid.
Lastly, I generally try to avoid SM_USER at all - because SM_USER is actually not a user attribute at all, but rather is "the login identifier used for authentication". If SiteMinder authenticates users via federation (e.g. SAML) or x509 authentication, SM_USER will be rather different than if a login form was used. Instead, its better in SiteMinder to set a "universal id" that is a user attribute, and appears in the headers as SM_UNIVERSALID. Your SiteMinder administrators will know how to do this (and may already have - look to see if you have a SM_UNIVERSALID header available already).
One other caution, in some SiteMinder configurations, the underscore will not be in the header name (use of the underscore is called "legacy" header mode in SiteMinder), so you might want to make your app configurable with respect to the header names, e.g. SMSERVERSESSIONID, SMUSER, SMUNIVERSALID etc.
If you want to programmatically re-validate a session, you can use the SiteMinder Agent API or REST API, or look at my company's product "SSO/Rest" which provides a comprehensive set of uniform REST interfaces to SiteMinder and also other SSO providers (http://www.idfconnect.com).
HTH!
-Richard
I am working on a project with PHP and angular. For the user sign in, we're using JWT. Still can't understand why we should use JWT instead of Sessions if each time the user browse a component we need to send the token to server code to check if the user still signed in or not.
Username and password will be sent to server code, where the authentication process will happen, and then generate a token and send it back to angular then save at the local storage.
Any comment on how JWT should be properly used.
EDIT
My question is about the process of checking the JWT when user surf the site and go from component into another.
If you use session for your application... Then while horizontal scaling sharing the session data becomes a burden ....you either need a specialised server .. Jwt are stateless and have no such requirement. It contain following data
Header - information about the signing algorithm, the type of payload (JWT) and so on in JSON format
Signature - well... the signature
Payload - the actual data (or claims if you like) in JSON format
Your JWT already is a proof of your authentication. So you have to send it with each request but you can simplify the authentication logic on server-side.
While on the login you will have to check the credentials you can rely on the JWT's signature and expiryDate. If the signature is still correct the token is valid and you do not have to authenticate anymore.
So regarding your horizontal authentication.
If the called service needs to be authenticated you have to check the JWT for validity on each request (normally works reasonably fast). If there are open api calls you can of course ignore the JWT on server side.
At the end of the day there is no difference to your "session" which will also send some "secret" key which maps your session context. Therefore, it will also be validated.
For some backends you can also use the JWT as your session key to get both worlds involved.
Example:
lets say you have two api roots:
api/secured/*
api/open/*
(Note that the secured and open are only here for demonstrative purposes)
The secured part will contain all the services you want to be authenticated.
The open part can contain insensitive data as well as your login services:
api/open/login -> returns your token
api/open/token/* -> refresh, check re-issue whatever you might need
So now lets say the user accesses your site. You will want to provde an authentication error if he tries to access any api/secured/* URL without a proper JWT.
In this case you can then redirect him to your login and create a token after authenticating him.
Now when he calls an api/secured/* URL your client implementation has to provide the JWT (Cookie, Request header, etc...).
Depending on your framework, language etc. you can now provide an interceptor/filter/handler on server side which will check:
If the JWT is present
if the signature is valid (otherwise the token was faked)
if the JWT is still valid (expiryDate)
Then you can act accordingly.
So to sum up:
There is no need to "authenticate" unless you want to create a new token.
In all other cases it is enough to check the validity of your JWT
I am trying to implement server-to-server integration with Dynamics CRM Online 2016 and BizTalk 2013 R2. I am using the WebHttpBinding to call the CRM web API, which requires a bearer token supplied as an http header:
Authorization: Bearer [base64string]
I have written a client message inspector which calls Azure AD using ADAL to acquire an access token. This is secured with a client assertion certificate, which is assigned to the registered app in our AD tenant:
var token = context.AcquireTokenAsync(this.ResourceUri, assertionCert).Result;
ResourceUri is https://[myorganisation].crm4.dynamics.com
assertionCert is a ClientAssertionCertificate created using the app registration application ID and an x509 certificate in the machine certificate store that is registered to the app as a KeyCredential
This 'works' in that it returns a token and I can decode this token to inspect the claims - there are a fair number of them, I have no way of telling whether this is the set of claims that CRM requires.
The AD app registration is configured with delegated permissions to the CRM instance.
I have set the application ID in the CRM local user to that of the app registration.
Upon calling the webAPI and supplying this token, CRM responds with 401 unauthorized.
I have repeated the same process in a powershell script and in PostMan, all of which appear to show the same behaviour.
What else am I supposed to do to make CRM accept my access token?
edit #1: Tried hardcoding the authority URI to https://login.windows.net/[my-tenant-id]/oauth2/token rather than what comes out of dynamically acquiring the authority through AuthenticationParameters - this is the same value except ending with /authorization instead of /token. This makes zero difference.
edit #2: An administrator I am working with pointed out to me that the application user I am expecting to use had no user roles assigned - this has been amended to have a role which should allow API access, but this also made no difference.
edit #3: Set oauth2AllowImplicitFlow to true in the manifest for the app registration. This doesn't make any difference.
edit #4: Made some progress by creating a new app registration, this time as a Native app rather than a web app. I managed to get a token using a client secret, and this was accepted - BUT when assigning a certificate to the app, and presenting a ClientAssertionCertificate as before, I get the response from the authority:
Error validating credentials. AADSTS50012: Client is public so a client_assertion' should not be presented.
WHY? What does 'Client is public' mean? Just work!
Hrrrmph!
Turns out that the original situation I had tried and failed with, now works.
Web application registration with delegated permissions to CRM Online
Install a client certificate on the client machine, and register this same certificate to the app using New-AzureADApplicationKeyCredential
Link the app registration to a CRM Application User created for this purpose (they are fundamentally different to interactive users) - n.b. this screen is not easy to find
Call AcquireTokenAsync() from ADAL
Just works
I am at a loss to explain why this didn't work the first time I tried it, as CRM doesn't supply any information as to why token validation failed.
I am implementing an app that connects to an OAuth2 server and it gets back a Json Web Token (JWT). I am passing the token along and I want to independently validate that the token came from the issuing source.
I can do this, no problem, with the public key from the issuing source. I have it available to me for now. Everything works.
But what if the OAuth server changes the signing key? How does the validating app get the new key? Is there a "best practices" convention for sharing the public key from an OAuth2 server? Do we just expose it from an endpoint on the auth server?
There's no solution that is standardized as part of the OAuth 2.0 protocol suite (today).
It was considered to be a single-domain problem that would be solved in various ways that were considered to be out of scope for the core OAuth specifications (much like the API between Resource Server and Authorization Server is/was), and much like any PKI based mechanism in general works today.
But OpenID Connect is a cross-domain SSO protocol that was built on top of OAuth 2.0, which also defined a more standardized option of dealing with key distribution in the form of JWKs URIs as part of the Discover, see the jwks_uri entry at:
REQUIRED. URL of the OP's JSON Web Key Set [JWK] document. This
contains the signing key(s) the RP uses to validate signatures from
the OP. The JWK Set MAY also contain the Server's encryption key(s),
which are used by RPs to encrypt requests to the Server. When both
signing and encryption keys are made available, a use (Key Use)
parameter value is REQUIRED for all keys in the referenced JWK Set to
indicate each key's intended usage. Although some algorithms allow the
same key to be used for both signatures and encryption, doing so is
NOT RECOMMENDED, as it is less secure. The JWK x5c parameter MAY be
used to provide X.509 representations of keys provided. When used, the
bare key values MUST still be present and MUST match those in the
certificate.
This would expose the key material over HTTPs protected channel, effectively leveraging the SSL CA for publishing and rollover of JWT signing key material.
At some point the jwks_uri definition may be part of the standardized OAuth 2.0 protocol extensions as well, but for now you'd have to rely on a custom agreement between Client and Authorization Server to do so. That may not be too hard to implement yourself though.
You may get lucky if your Authorization Server happens to be an OpenID Connect provider as well and uses the same key material for signing ID tokens as well as JWT access tokens.
Updated 4/22/2019: the Authorization Server metadata document is now also standardized it its own OAuth 2.0 extension OAuth 2.0 Authorization Server Metadata RFC8414