How to process SAML Response in Nodejs to validate SAML response - node.js

I am new to SAML and have recently tried the SAML POC using Azure AD as Identity provider(Idp) and Dropbox as Service provider(SP) and was able to successfully authenticate and login to Dropbox.
I want to programmatically process(validate) the SAML response token that was returned by Identity provider so that I can login to service provider.
I am looking for guidance/pointers/reference around processing and validating SAML Token in Nodejs, so that I can authenticate user against Service Provider.
Any help would be appreciated.

I'm using the following library to perform SAML response validation:
https://github.com/node-saml/node-saml
It has straightforward instructions as to how SAML is to be parsed.
For diving deeper into SAML flow, check this video: https://www.youtube.com/watch?v=l-6QSEqDJPo
To get started, simply install library using:
npm i node-saml
Then, use the library as follows:
const { SAML } = require("node-saml");
const options = {};
const saml = new SAML(options);
For passing the right Options, you can refer here: https://github.com/node-saml/node-saml
Another alternative is to use passport-saml, linked here: https://www.npmjs.com/package/passport-saml

Related

Getting Error AADB2C99067 when trying to request access token from Azure B2C

I have an Azure AD B2C tenant setup with an Angular app on the front-end using Authorization Code Flow with PKCE and a back-end api. Everything is working fine. I now have a need to allow the user to access certain pages on the front-end anonymously. I would prefer to still protect the apis these pages will call using the same access token.
I have followed the article here to set up Client Credentials flow. I am able to get an access token successfully using Postman and use it to call my back-end apis fine. However, when I try to do the same from the Angular app, I get the following error:
{"error":"invalid_request","error_description":"AADB2C99067: Public Client XXXXX-XXXXXX is not supported for Client Credentials Grant Flow\r\nCorrelation ID: 2b3346ef-1828-4900-b890-06cdb8e0bb52\r\nTimestamp: 2022-07-28 04:12:21Z\r\n"}
Below is the code snippet I am using in Angular to retrieve the access token.
const urlencoded = new URLSearchParams();
urlencoded.set('grant_type', 'client_credentials');
urlencoded.set('client_id', '<clientid>');
urlencoded.set('client_secret', '<clientsecret>');
urlencoded.set('scope', '<scope>');
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' }),
};
const url = 'https://<b2ctenant>.b2clogin.com/<b2ctenant>.onmicrosoft.com/<customPolicy>/oauth2/v2.0/token';
return this.httpClient.post(url, urlencoded, httpOptions);
Any ideas what could be missing?
Thanks!
Though azureadb2c supports client_credential flow.One may not use them with SPA apps.
This scenario is not supported by MSAL.js. Client credential flow/ grant type will not work in SPAs(Angular) because browsers cannot securely keep client secrets.
As they may end up in the browser, visible to everyone and to attackers that load them.
Note:As the application's own credentials itself are being used, they must be kept safe - never publish that credential in your source
code
If you are using it for web app , please make sure to select the platform as web or change the reply url type to be web.
"replyUrlsWithType": [
{
"url": "https......",
"type": "Web"
},
]
Please refer :
Configure authentication in a sample Angular SPA by using Azure
Active Directory B2C | Microsoft Docs
OAuth 2.0 client credentials flow on the Microsoft identity platform- Microsoft Entra | Microsoft Docs

Access Web API(Nodejs) using ROPC Azure B2C flow (Without browser login)

I have Web API which is an NodeJs code. In Web API we have protect API using (passport.authenticate('oauth-bearer', {session: false}).
When generating token using ROPC app in postman, Access token is generated but at the time of authorization
var bearerStrategy = new BearerStrategy(options,
function (token, done) {
console.log(options);
console.log(token);
// Send user info using the second argument
done(null, {}, token);
}
);
This will return unauthorized.
I have added scope and configure Native and Web API as per document.
This issue was solved by #Sruthi comment, add it as the answer to close the question:
For login.microsoftonline.com, it is generally used to perform a
login request for Azure ad tenants to obtain tokens. For b2c
tenants, you need to use tenant-name.b2clogin.com to perform the
request.
Use ROPC flow to get access token:
POST https://<tenant-name>.b2clogin.com/<tenant-name>.onmicrosoft.com/B2C_1_ROPC_Auth/oauth2/v2.0/token
username=<username>
&password=<Passxword>
&grant_type=password
&scope=openid+app_id+offline_access
&client_id=<client_id>
&response_type=token+id_token
(Moving from comments to Answer).
You can get access token using curl for ROPC curl -X POST -d "client_id=Clientid&scope=openid+appid+offline_access&grant_type=password&username=username&password=password&response_type=token" https://<tenant-name>.b2clogin.com/<tenant-name>.onmicrosoft.com/B2C_1_ROPC_Auth/oauth2/v2.0/token'
As you are using old origin URL which is login.microsoftonline.com should no longer refer to your applications and APIs. Instead, use b2clogin.com for all new applications, and migrate existing applications from login.microsoftonline.com to b2clogin.com. Please refer to the official document

How do I authorize a service to call an API using Azure Active Directory?

I have a service that gets an access token from Azure AD. I have an API that I would like to accept that token as authorization.
My service code to call the API is
HttpClient client = new HttpClient()
{
BaseAddress = new Uri("https://localhost:44372/")
};
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, client.BaseAddress + "api/todolist");
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);
HttpResponseMessage response = await client.SendAsync(request);
The response I get back is a 401 - Unauthorized.
I have a feeling that the issue is in the API ConfigureServices function; specifically (this was taken from an example, so I don't really know what it means yet):
services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options =>
{
options.TokenValidationParameters.RoleClaimType = "roles";
});
I'm new to Azure and authentication in general so I don't know what options are available or appropriate. I also am not sure how to set up the applications in Azure to allow this. I have the application id of the service set up as an Authorized client application of the API; it is also listed int the knownClientApplications in the API manifest.
There are just so many knobs to turn, I have no idea where to go from here. If anyone can let me know some things to try, that would be outstanding.
Thanks
Here is a code sample on how to call a web API in an ASP.NET Core web app using Azure AD:
https://learn.microsoft.com/en-us/samples/azure-samples/active-directory-dotnet-webapp-webapi-openidconnect-aspnetcore/calling-a-web-api-in-an-aspnet-core-web-application-using-azure-ad/
This sample contains a web API running on ASP.NET Core 2.0 protected by Azure AD. The web API is accessed by an ASP.NET Core 2.0 web application on behalf of the signed-in user. The ASP.NET Web application uses the OpenID Connect middleware and the Active Directory Authentication Library (ADAL.NET) to obtain a JWT bearer token for the signed-in user using the OAuth 2.0 protocol. The bearer token is passed to the web API, which validates the token and authorizes the user using the JWT bearer authentication middleware.

ADAL failed to return token in webAPI. Error:Invalid jwt token using userassersion

A native app created which is calling web api.Two apps has been created in the azure.Here is the code code for getting access token and it worked well,I am getting access token:
UserCredential uc = new UserPasswordCredential(userName, password);
result = authContext.AcquireTokenAsync(todoListResourceId,clientId,
uc).Result;
Now to access new token after the expiry of old one(1 hr) i am using the code:
AuthenticationContext authContext = new AuthenticationContext(authority);
UserAssertion userAssertion = new UserAssertion(oldToken, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName);
AuthenticationResult result = authContext.AcquireTokenAsync(todoListResourceId, clientId, userAssertion).ConfigureAwait(false).GetAwaiter().GetResult();
But I am getting Error as:"Invalid JWT token. AADSTS50027: Invalid JWT token. Token format not valid".
Checked JWT token :it is correct in format can able to decode using jwt.io.
Note: client Id am using for these two code snippet are the same appId.
I know this is the exact duplication of the question asked by devangi.I cannot able to comment on that question that's why I am asking it again.
Any one can able to help me out?
Or
It will be great if any one can able to help with other ways to get token with out using user password since i need to internally generate new token without user enter password again.
For the scenario when user has authenticated on a native application, and this native application needs to call a web API. Azure AD issues a JWT access token to call the web API. If the web API needs to call another downstream web API, it can use the on-behalf-of flow to delegate the user’s identity and authenticate to the second-tier web API .
Please refer to this document for more details about On-Behalf-Of flow . You can also refer to code sample .
For the scenario when when a daemon application(Your web api) needs to call a web API without user's identity , you should use client credential flow to use its own credentials instead of impersonating a user, to authenticate when calling another web service. Code sample here is for your reference .
Please click here for explanation about above two scenarios. Your code is using Resource Owner Password Credentials Grant ,this flow has multi restrictions such as don't support 2FA and is not recommended .
If i misunderstand your requirement , please feel free to let me know .

Azure AD OpenIDConnect + ASP.NET Core - Authenticate and Extra Permissions/Token?

I am using the following bits against my Azure AD to authenticate with ASP.NET Core.
https://azure.microsoft.com/en-us/resources/samples/active-directory-dotnet-webapp-openidconnect-aspnetcore/
https://github.com/Azure-Samples/active-directory-dotnet-webapp-openidconnect-aspnetcore
I have the basic login/auth working after creating an Azure AD app. User can login/logout.
My question is given this, what's the best way when a user Auth's to log to a DB? I thought about making the redirect URL to an endpoint, saving, then just redirecting back to "Home" but is that ideal?
Also, is it possible to retrieve a bearer token via this approach? Or does this require another type of call or extending "scope"? So that for example I could retrieve the authenticated users Manager.
https://graph.microsoft.com/v1.0/me/manager
My question is given this, what's the best way when a user Auth's to log to a DB? I thought about making the redirect URL to an endpoint, saving, then just redirecting back to "Home" but is that ideal?
This way only able to log those who already sign-in your app successfully. It is not able to log those users who are attempt to sign-in your app but enter the wrong password.
Azure AD already provide lots of report to gain visibility into the integrity and security of your organization’s directory.( refer here)
And if you are using the Azure AD Premium, you can review the sign-in activities via the Azure new portal below:
And if you want to store the sign-in activity in your web app, you can write the custom code after the token is verified. Here is the code for your reference:
// Configure the OWIN pipeline to use OpenID Connect auth.
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
ClientId = Configuration["AzureAD:ClientId"],
Authority = String.Format(Configuration["AzureAd:AadInstance"], Configuration["AzureAd:Tenant"]),
ResponseType = OpenIdConnectResponseType.IdToken,
PostLogoutRedirectUri = Configuration["AzureAd:PostLogoutRedirectUri"],
Events = new OpenIdConnectEvents
{
OnRemoteFailure = OnAuthenticationFailed,
OnTokenValidated = context => {
//write the custom code to store users login-in
return Task.FromResult(0); }
},
});
Also, is it possible to retrieve a bearer token via this approach?
Yes. We can get the token after receive the authorization code. You can refer the code sample here to acquire the token from asp.net core app.

Resources