Are there security concerns exposing the clientId and tenant in client side code when using adal/adal-angular.js - angularjs

I'm in the process of implementing AAD single sign on in our application and we will be using the adal.js/adal-angular.js library with our MEAN stack application. Part of initializing the library is to call init() and provide the tenant and clientId
adalProvider.init(
{
tenant: "mycompany.onmicrosoft.com",
clientId: "05bdd8d7-XXXX-XXXX-XXXX-5f2769f8b9b6"
},
$httpProvider
);
for example.
If someone views the source and takes the tenant and clientId can they use that somehow in their own application maliciously?
Does AzureAD check the URL the request came from and block it if it's not the configured login url?
Seems as though the clientId is more like a public key but if the only 2 things needed for an app to trigger authentication with AzureAD is the tenant and clientId and those are exposed client side in source code that someone could use them to create a phishing site X or to grab id_tokens if the request is redirected back to their site X rather than the original site
Does Azure rely on the configured settings in the application setup and protect against this?
I'm still getting a grasp on the OpenID Connect and OAUTH 2.0 finer points so forgive me if this question has an obvious answer.

Adal.js uses the Implicit flow (as per OpenID connect / oAuth 2 specifications) and exposing the ClientID (and tenant id of AAD) doesn't pose any security risk.
While registering the Clients in Azure AD administration panel, we specify a Redirect URI for the client. This is the Application URL for which users will get redirected after successful authentication.
So even if a malicious client tries to use your clientid and tenant id, the users will be redirected back to the registered URI(which is your app) after authentication and not to the malicious site
In implicit flow the application doesn't collect any username / password, IDP/OP (i.e AAD) manages this part - so user credentials won't be compromised as well
**For other flow types (Authorization code, Client credentials,etc) we have something called client-password along with ClientID. This shouldn't be exposed to public clients.

Related

Azure AD Enterprise Application - Identify Caller Application

I have a REST API which uses Azure ADD App registration to allow other apps to call it.
In the Azure Portal, I have registered it as an Enterprise Application and also registered the consumer applications and assigned them Roles appropriately.
The authentication and RBAC works fine.
But the use case that I am working on requires me to identify and log the incoming request calling application's name (The one seen in the portal as 'Display Name', when we view the list of users and groups for an enterprise Application).
As advised in the internet, I am using some Identity related API to read the claims from the request header.
var provider = claimsUser.FindFirst("http://schemas.microsoft.com/identity/claims/identityprovider").Value;
var sid = claimsUser.FindFirst(ClaimTypes.NameIdentifier).Value;
OR
var sid = claimsUser.FindFirst("stable_sid").Value;
But this gives me a GUID value which I couldn't map to any of the consumers of the Enterprise Application.
The clients are all registered in the Azure portal.
In the Portal, I can see the apps in the "Users and Groups" section for the Enterprise application, with their appropriate roles.
In terms of usage, before making the call, the clients generate a bearer token based on the certificate that they get from Azure. The make the call with the bearer token attached to the request header. This bearer token is validated against the Azure AD, in the filters set before every controller..
What I want is to get are the details about this client who has made the call.. As per some repliers, and, to which I agree, the Guid that I get as part of the previous call mentioned above is for the actual user and not the app itself which is making the call.
Can anyone throw some light into it.. some code snippet will be of real help..
I'm not sure what authentication flow you are using, but SID is generally for a user that's logged in, not an application. if your client applications are using client id and secret, the token it returns that you send to the api should include the app registration guid. https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow#access-control-lists . So the appid and iss should give you the guid of the app registration. using this, you can make a call to graph api, to identify the display name of the app registration. https://learn.microsoft.com/en-us/graph/api/application-get?view=graph-rest-1.0&tabs=http
If your app is a user login app, and you don't want to make a call to graph, the other option you could do as a workaround would be to create app roles and assign users to them but name the app roles with some convention that includes the app's display name. then the name could come through under roles claim.. https://learn.microsoft.com/en-us/azure/active-directory/develop/howto-add-app-roles-in-azure-ad-apps
those are some options.. but other than calling graph or kinda working around to inject the name into a different claim of the token I'm not sure of any other method to get the "app registration's display name"

IdentityServer4 - Understanding flows and Endpoints. How is it related to OAuth and OpenIDConnect?

I am integrating the security aspect of webapplication. I have decided to use OAuth,
so we have a REST WebApi in AspNet Core 3.0, the client which is a SPA created in React, and the Identity Server 4.0 app which is also in AspNet Core 3.0.
I read that OAuth is created for Authorization and not for Authentication.
For Authentication, seems that exists something else called OpenIDConnect, so the first question that comes to my mind, and on which I cannot find an easy answer is: are OAuth, OpenIDConnect and IdentityServer related technology?
Which is the best solution for authentication, considering that I would like to create users in a SqlServer Database, and if it's possible I would like to use Entity Framework for the porpose?
The flow for my authentication would be:
User writes Username and Password, if they are right he receive the JWT Token, without redirecting him/her to the authorization page.
At this point the problem are:
which is the right endpoint to do this flow:
is it the /authorize or the /token endpoint?
I have a lot of confusion for the questions above.
The second thing, what is the best way to retrieve the user informations?
For example if my endpoint needs to understand from the logged in user what are his data, I think that or I retrieve from the endpoint or from the JWT token.
Even here I have no clue on which is the best.
I read that OAuth is created for Authorization and not for Authentication. For Authentication, seems that exists something else called OpenIDConnect, so the first question that comes to my mind, and on which I cannot find an easy answer is: are OAuth, OpenIDConnect and IdentityServer related technology?
That's right. OAuth was the first one introduced and allows the person requesting it access to the resources (its handing out access tokens). OIDC (OpenID Connect) on the other-side extends this concept by an identity, the authentication part.
The identity token verifies the identity of the person to your application. Instead of providing identity via username + password (i.e. user creating an account on your website), they get redirected to your authentication provider/app and enter their login there and you get an identity token in return (and/or an access token, depending on the flow and scopes you request).
The identity token is an JWT token (or reference token). The JWT token contains all of the users identity information required for your application (user id, email, displayname, age, etc.) and is cryptographically signed. Only the Identity Server knows the key used to sign it up and you can verify it with the public key from the OIDC (IdSrv here) provider.
Reference token works similar, but claims are requested on the server side and cached.
With identity token you can not access the users resources. Example: Facebook.
When you sign in your application with an facebook account, most page will only request identity token to verify that its the same user (instead of using a username / password combination). But with that one, the application can't access your facebook posts or do posts in your name.
If the application requests an access token (token scope), then also an access token will be returned (if the application is allowed to via allowed scopes). You will be asked to grant the permissions to the resources which the application requests.
With that token, the application can read your posts or post in your name.
Which is the best solution for authentication, considering that I would like to create users in a SqlServer Database, and if it's possible I would like to use Entity Framework for the porpose?
Doesn't really matter. Either one can be used, all you really need is the "sid" (subject id) claim and associate that one with your user.
Identity Server can issue both, depending on what the client asks (if client asks for id_token response type, it will receive an identity token, if it asks for token an access token. Both can be specified or just one).
At this point the problem are: which is the right endpoint to do this flow: is it the /authorize or the /token endpoint? I have a lot of confusion for the questions above.
/authorize is used to authorize the user (have him login, and send back to your website). Its used for so called interactive flows, where the user enters credentials
/token endpoint you can only retrieve a token (resource owner flow (username + password), client credentials (for machine to machine authentication), refresh token (to get a new access token by using an refresh token (if you asked for offline_access scope, which gives and refresh token)
The second thing, what is the best way to retrieve the user informations?
the /userinfo endpoint, see docs: http://docs.identityserver.io/en/latest/endpoints/userinfo.html
As the doc says to access that, the client needs to request the openid scope.
For example if my endpoint needs to understand from the logged in user what are his data, I think that or I retrieve from the endpoint or from the JWT token.
Yes you can retrieve it from JWT token, if you use JWT token. If you use reference token, its just an ID.
And last but not least the /introspection endpoint can be used to validate the token (if your consuming application has no libraries to decrypt and validate signature of the token.
If you can, its best to use the Identity Server client libraries (i.e. IdentityServer4.AccessTokenValidation package for ASP.NET Core or oidc-client for npm/javascript based applications) which should be picking up the correct endpoints, so you don't have to worry about it

IdenityServer4 - doesn't redirect after MFA

My Auth Server uses IdentityServer4.
Redirect configured as follows for a client
RedirectUris = new List<string>
{
"https://localhost:44342/signin-oidc"
}
this works fine for those users for whom MFA is not enabled. But when it is enabled, and kicks in, the redirect doesn't work. After successful 2nd FA, user stays back on the AuthServer page.
Any idea why?
Multifactor authentication is not implemented by Identityserver4. Identityserver4 is about how the third party application gets access to protected resources on behalf of the user.
The means of how the user gets authenticated are out of the identityserver4 scope. In other words, this is not related to identityserver4.
If you're using the identityserver4 quickstart it comes with ASPNET Identity, ASPNET Identity provides you with a local authentication system for ASPNET applications. MultiFactor Authentication is probably there.
Being said that, when you try to POST to the /authorize endpoint (note authorize not authenticate) from your client application IdentityServer tries to authorize your request and to do so it makes you authenticate first, by presenting you the Login Form.
If you look at the Address bar on this point, you'll notice there's an encoded url as returnUrl param, on the controller code you'll see a check that if that param is present, redirect to that url after successful login.
So, check the flow on your application and see where does that parameter get lost on the redirect hell, at some point you're not passing the returnUrl.

IdentityServer4 Maintain Session Id across different authentication flows

I am using Identityserver4 as an OIDC Athentication Server using both clientCredentials flow and OIDC Implicit flow. My Setup is this
Client Website (Needs a JWT for some front-end decisions)
IdentityServer4 Authentication Server
API (Needs a JWT for back-end Authorization)
When someone first visits the client website a call is made to IdentityServer using the clientCredentials flow. This allows the user (Name: GUEST, user_id= null) limited access to the API (including adding items to a basket).
When the user logs in, they get a new token from IdentityServer along with new user claims (Name: BOB, user_id=1) which is fine.
My question is, how does the API know that the logged in user BOB was GUEST.
I have tried many things with IdentityServer including
1) Client Website: Add acrValue = client session.id but i can't figure out how to read this in Indentityserver and set it as a claim
2) Client Website: Add IdTokenHint = client session.id but, again, don't know how to read this in IdentityServer and set it as a Claim
3) Enabled 'IncludeJwtId' on my client configuration. When doing this a 'jti' claim is returned after a clientCredentials call but is missing after an implicit grant flow.
4) After an Implicit Grant flow the returned JWT has an 'sid' but is useless as it wasn't included in the original JWT from the clientCredentials flow.
I guess i would like to send a client sessionId as part of the clientCredentitals flow and also when the user logs in using the implicit flow. This way i could store the id in the JWT in both cases.
I feel like i'm missing something obvious. Does anyone know how i can maintain a sessionId across the clientCredentials flow and the implicit flow?
Thanks in advance.
My question is, how does the API know that the logged in user BOB was
GUEST.
I'm afraid that's up to your client app/API business logic.
I guess i would like to send a client sessionId as part of the
clientCredentitals flow and also when the user logs in using the
implicit flow. This way i could store the id in the JWT in both cases.
And this is simple if you involve delegation.

How to configure on-behalf-of authentication in multi-tenant environment?

I have a native client that calls a service I wrote-- that in turn calls the Graph API (using the original caller's credentials).
This is exactly like the 'onbehalfof' sample found here (my code fails the same way as the sample):
https://github.com/Azure-Samples/active-directory-dotnet-webapi-onbehalfof
When logging in as a user from the same tenant as the service (tenant A), everything works fine (just like the onbehalf of sample). When logging in as a user from a different tenant (tenant B), I get an exception on this line in the service:
result = await authContext.AcquireTokenAsync(GraphResourceId, clientCred, userAssertion);
(this is line 153 from TodoListController.cs in the onbehalfof sample).
The exception is this:
AADSTS65001: The user or administrator has not consented to use the
application with ID 'de2fb28b-83f8-419d-9b00-3fbce0a60bf4'. Send an
interactive authorization request for this user and resource.\r\nTrace
ID: 6865c420-674a-4adf-a070-3d9b9c500200\r\nCorrelation ID:
7e088563-d7fe-4131-a05c-cbe04dbb2bbd\r\nTimestamp: 2017-03-29
22:56:58Z
The application id above refers to the service I wrote (which is the same line in the TodoListService in the onbehalfofsample).
I configured everything for multi-tenant authentication. But it's the additional call that my service is making to another service (Graph API) that's causing the problem. What additional configuration do I need to do in the Azure portal to make this work?
In the instructions written for the sample you linked above, they address this issue with the following section:
Configure known client applications
For the middle tier web API to be able to call the downstream web API,
the user must grant the middle tier permission to do so in the form of
consent. Because the middle tier has no interactive UI of its own, you
need to explicitly bind the client app registration in Azure AD with
the registration for the web API, which merges the consent required by
both the client & middle tier into a single dialog. You can do so by
adding the "Client ID" of the client app, to the manifest of the web
API in the knownClientApplications property. Here's how:
Navigate to your 'TodoListService' app registration, and open the manifest editor.
In the manifest, locate the knownClientApplications array property, and add the Client ID of your client application as an element.
Your code should look like the following after you're done:
"knownClientApplications": ["94da0930-763f-45c7-8d26-04d5938baab2"]
Save the TodoListService manifest by clicking the "Save" button.
My assumption is that because you are running into this problem, that you have not done this special configuration.
The other option you have is to explicitly request consent between the middle tier and the AAD Graph API. You can do this by having a tenant administrator 'login' and consent to your middle tier service. All you need to do is generate a login url with the middle tier App ID.
However, I strongly recommend you do it the documented way, since this will provide a better experience for your users.
It's working now. I had to make two changes to get it working.
First, on the service side switch to using "common" as the tenant. I had switched to common on the client but didn't realize you had to do this on the service side as well:
<add key="ida:Tenant" value="common" />
Second, change the GraphUserUrl on the service to the following URL:
<add key="ida:GraphUserUrl" value="https://graph.windows.net/me?api-version=1.6" />
The original URL in the sample didn't work (at least for users in another tenant).
Here's the consent dialog that appears when a user from another tenant logs in:
Consent Dialog
Here's my client manifest...
Client Manifest
...and my service manifest...
Service Manifest

Resources