Asp.Net Core Api Authorization - reactjs

I have an Asp.Net Core / ReactJs aopplication. I'm using Microsoft.AspNetCore.ApiAuthorization.IdentityServer to authenticate the API. However, I'm getting an error, which I believe is down to bad configuration.
If I run this locally, with the following config, everything works, and the app redirects to the log-in screen as expected:
"IdentityServer": {
"Clients": {
"MyApp": {
"Profile": "IdentityServerSPA",
}
},
"Key": {
"Type": "File",
"FilePath": "Assets/selfsignedcert.pfx",
"Password": "password"
}
},
However, if I change the config to the following:
"IdentityServer": {
"Clients": {
"MyApp": {
"Profile": "IdentityServerSPA",
"RedirectUri": "https://localhost:5211/authentication/login-callback"
"LogoutUri": "https://localhost:5211/authentication/logout-callback"
}
},
"Key": {
"Type": "File",
"FilePath": "Assets/selfsignedcert.pfx",
"Password": "password"
}
},
It errors (redirecting to the following):
https://localhost:5211/home/error?errorId=1234...
Looking at the auth request, from the client, they are exactly the same; however the second returns an error, while the first successfully redirects.
Is there something wrong with my config? Alternatively, how can I debug this issue?

Both of your Uris in the non-working configuration point to logout. Is this really what you're trying to do?
In the first configuration, you're not defining any Uris, so they will have the following default values:
The redirect_uri defaults to /authentication/login-callback.
The post_logout_redirect_uri defaults to /authentication/logout-callback.
As documented here
Try changing the second configuration to match the default values to see if that helps.

The client configuration of redirect_uri and post_logout_redirect_uri must be identical to the IDP:
redirect_uri: 'https://localhost:5211/authentication/login-callback',
post_logout_redirect_uri: 'https://localhost:5211/authentication/logout-callback',
Or
redirect_uri: $'{IDPhost_config}/authentication/login-callback',
post_logout_redirect_uri: $'{IDPhost_config}/authentication/logout-callback',

Related

Struggling with optional claims in id/access token

I am updating an internally developed single-page app (Typescript/React) that uses OAuth2 from AD-FS 2016 to Azure AD v2. Things are complicated slightly by the fact that I (the developer) don't have direct access to the Azure console and am working on this with a (non-developer) sysadmin who does.
I have implemented PKCE and got the flow working; I can now obtain JWT access, ID and refresh tokens from the server and authenticate them via JWKS. So far so good.
Now, my apps to know a couple more things:
whether or not the user should be treated as an administrator. This is inferred from group memberships
the preferred username and first name/surname of the user
The first of these we dealt with by setting up a "role" and mapping it out to groups in the Azure console. We then added the role claim to the tokens. I can find this as a string array in "id_token". No problem.
I was confused for a while because I was looking for it in "access_token", but it's not a problem for my app to use "id_token" instead.
The second is the thing that is really giving us problems. No matter what we put into the "optional claims" dialog - we've added all these fields and more, for the ID token, they do not appear in it. Nothing we are doing seems to affect the actual tokens that come out at all.
I am beginning to think that I have missed something out with regards to obtaining the information. I am using the https://graph.microsoft.com/profile, https://graph.microsoft.com/email and https://graph.microsoft.com/user.read scopes and the administrator has authorized these on behalf of the app. The user is synced from our in-house active directory, which the AD-FS is running from as well, so I know that this information is in there. I tried messing with the resource parameter but this is deprecated in Azure AD v2 apparently.
I've read and re-read https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-optional-claims along with other online documentation, and the following passage confuses me and makes me think that the issue might be related to scopes:
Access tokens are always generated using the manifest of the resource, not the client. So in the request ...scope=https://graph.microsoft.com/user.read... the resource is the Microsoft Graph API. Thus, the access token is created using the Microsoft Graph API manifest, not the client's manifest. Changing the manifest for your application will never cause tokens for the Microsoft Graph API to look different. In order to validate that your accessToken changes are in effect, request a token for your application, not another app.
Or is that just the reason that I switched to using the id_token?
The optional_claims section of the configuration manifest looks like this:
"optionalClaims": {
"idToken": [
{
"name": "email",
"source": null,
"essential": false,
"additionalProperties": []
},
{
"name": "upn",
"source": null,
"essential": false,
"additionalProperties": []
},
{
"name": "groups",
"source": null,
"essential": false,
"additionalProperties": []
},
{
"name": "family_name",
"source": null,
"essential": false,
"additionalProperties": []
},
{
"name": "given_name",
"source": null,
"essential": false,
"additionalProperties": []
},
{
"name": "preferred_username",
"source": null,
"essential": false,
"additionalProperties": []
}
],
"accessToken": [
{
"name": "email",
"source": null,
"essential": false,
"additionalProperties": []
},
{
"name": "groups",
"source": null,
"essential": false,
"additionalProperties": []
},
{
"name": "preferred_username",
"source": null,
"essential": false,
"additionalProperties": []
}
],
"saml2Token": [
{
"name": "groups",
"source": null,
"essential": false,
"additionalProperties": []
}
]
},
But the resulting payload in the ID tag looks like this:
{
"aud": "redacted",
"iss": "https://login.microsoftonline.com/redacted/v2.0",
"iat": 1654770319,
"nbf": 1654770319,
"exp": 1654774219,
"email": "redacted",
"groups": [
"redacted",
"redacted",
"redacted",
"redacted"
],
"rh": "redacted",
"roles": [
"redacted"
],
"sub": "redacted",
"tid": "redacted",
"uti": "redacted",
"ver": "2.0"
}
Can anyone who has more experience of the platform help me understand what we are doing wrong here? Do we need to define custom scopes? Have we simply forgotten to turn an option on?
All help gratefully received! Thanks in advance...
I tried to reproduce the same in my environment and got below results:
I have implemented PKCE flow and got JWT access, ID and refresh tokens.
I added optional claims like below:
Go to Azure Portal -> Azure Active Directory -> App Registrations -> Your App -> Token Configuration
Please check the scopes you are using to get token.
When I gave only openid as scope, got response like below:
But when I gave scope as openid profile email user.read, got all optional claims successfully like below:

Why is Google App Engine throwing access forbidden errors?

Could really use some help here. I have a GAE NodeJS app in the standard environment. Until a few days ago (09/23) it was running just fine, it would respond to requests as expected, etc.
Today, the app responds with 403's when I try to make any request to my appspot url. I'm 100% certain this is not a code issue, as if I deploy the same code to GAE in another project, it works fine. Furthermore, the only firewall rule is a wildcard to allow all traffic.
Edit: adding the only relevant-looking log entry I see from the project:
{
"protoPayload": {
"#type": "type.googleapis.com/google.cloud.audit.AuditLog",
"status": {},
"authenticationInfo": {
"principalEmail": "address#domain.com"
},
"requestMetadata": {
"callerIp": "x.x.x.x",
"requestAttributes": {
"time": "2021-09-23T15:04:05.198927Z",
"auth": {}
},
"destinationAttributes": {}
},
"serviceName": "appengine.googleapis.com",
"methodName": "google.appengine.v1.Services.UpdateService",
"authorizationInfo": [
{
"resource": "apps/my-google-cloud-project-id/services/default",
"permission": "appengine.services.update",
"granted": true,
"resourceAttributes": {}
}
],
"resourceName": "apps/my-google-cloud-project-id/services/default",
"serviceData": {
"#type": "type.googleapis.com/google.appengine.v1.AuditData",
"updateService": {
"request": {
"name": "apps/my-google-cloud-project-id/services/default",
"service": {
"networkSettings": {
"ingressTrafficAllowed": "INGRESS_TRAFFIC_ALLOWED_INTERNAL_AND_LB"
}
},
"updateMask": "networkSettings"
}
}
},
"resourceLocation": {
"currentLocations": [
"us-east1"
]
}
},
"insertId": "an-id",
"resource": {
"type": "gae_app",
"labels": {
"project_id": "my-google-cloud-project-id",
"zone": "",
"module_id": "default",
"version_id": ""
}
},
"timestamp": "2021-09-23T15:04:05.131761Z",
"severity": "NOTICE",
"logName": "projects/my-google-cloud-project-id/logs/cloudaudit.googleapis.com%2Factivity",
"operation": {
"id": "some-operation-uuid",
"producer": "appengine.googleapis.com/admin",
"first": true
},
"receiveTimestamp": "2021-09-23T15:04:05.495890906Z"
}
I don't recall making this change, and I'm not sure what the ingressTrafficAllowed value was before.
Somehow the ingress setting on the GAE service got changed. I believe that issue was fixed by going to GCP console > App Engine > Services > select affected service(s) -> Edit ingress setting from the top, and select the appropriate value.
I say I believe this fixed the issue as I was still getting 403's on my appspot url after doing this, and ultimately I ended up deleting and re-creating the project from scratch, which got everything working again. Clearly there was some misconfiguration somewhere in my project, but GCP does not make it easy to diagnose what the issue might be.

ASP.NET Zero solution for both identityserver and client

Before getting into the issue, let me tell you what I am trying to achieve.
I need to implement sort of SSO in all of my applications. For which I want to use ASP.NET Zero solutions as
SSO Provider as well as Clients.
Is it possible or am I overthinking?
I am using ASP.NET Zero template: ASP.NET Core - MVC & jQuery
I am very new to IdentityServer and OpenId so please excuse for my silly mistakes if I have made.
In one of ABP project, I have added a static client to IdentityServer AppSettings like below.
First project's AppSettings - Hosted application
{
"ClientId": "localhost",
"ClientName": "MVC Client Demo",
"AllowedGrantTypes": [
"implicit"
],
"RequireConsent": "true",
"ClientSecrets": [
{
"Value": "test"
}
],
"RedirectUris": [
"https://localhost:44302/signin-oidc"
],
"PostLogoutRedirectUris": [
"https://localhost:44302/Account/Login"
],
"AllowedScopes": [
"openid",
"profile",
"email",
"phone",
"default-api"
],
"AllowOfflineAccess": "true"
}
Now from my second ABP project (localhost), I am trying to enable OpenId to authenticated through above server.
Second project's AppSettings - Running on localhost
"OpenId": {
"IsEnabled": "true",
"Authority": "https://[applicationname].azurewebsites.net/",
"ClientId": "localhost",
"ClientSecret": "test",
"ValidateIssuer": "true",
"ClaimsMapping": [
{
"claim": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
"key": "http://schemas.microsoft.com/identity/claims/objectidentifier"
}
]
}
However I am not getting any error, in logs I can see there is a message that says:
AuthenticationScheme: Identity.External signed in.
And a cookie is being created with key "Identity.External" but login-is not happening successfully.
Inside AccountController below line returns null and that resulting into unsuccessful login.
**var externalLoginInfo = await _signInManager.GetExternalLoginInfoAsync();**
if (externalLoginInfo == null)
{
Logger.Warn("Could not get information from external login.");
return RedirectToAction(nameof(Login));
}
Try adding
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier);
before services.AddAuthentication()
This will map sub claim to NameIdentifier claim so GetExternalLoginInfoAsync will not return null.

Ask for how to get user profile after callback

My web application is using Single Sign On (SSO) service from IBM Bluemix. This is the credentials info of my SSO service:
{
"SingleSignOn": [
{
"credentials": {
"secret": "MYSECRET",
"tokenEndpointUrl": "https://adminwebsso-jjjfvxi6wy-cq17.iam.ibmcloud.com/idaas/oidc/endpoint/default/token",
"authorizationEndpointUrl": "https://adminwebsso-jjjfvxi6wy-cq17.iam.ibmcloud.com/idaas/oidc/endpoint/default/authorize",
"issuerIdentifier": "adminwebsso-jjjfvxi6wy-cq17.iam.ibmcloud.com",
"clientId": "MYCLIENTID",
"serverSupportedScope": [
"openid"
]
},
"syslog_drain_url": null,
"volume_mounts": [],
"label": "SingleSignOn",
"provider": null,
"plan": "professional",
"name": "VA-Admin-Console-R1-SSO",
"tags": [
"security",
"ibm_created",
"ibm_dedicated_public"
]
}
]
}
From my Application, I redirect to Login page of IBM like URL:
https://adminwebsso-jjjfvxi6wy-cq17.iam.ibmcloud.com/idaas/oidc/endpoint/default/authorize?response_type=code&client_id=MYCLIENTID&redirect_uri=http://localhost/callbackā‰»ope=openid%20openid
After login success IBM redirect to my web application, I can get parameter "code" from callback URL (http://localhost/callback?scope=openid&code=bngM6aV5cYHAvhv7wLAM5QSWFDARn7).
From there, I use the "code" to to get user profile. I have try to use AJAX to get user profile:
var settings = {
"async": true,
"crossDomain": true,
"url": "https://idaas.ng.bluemix.net/sps/oauth20sp/oauth20/token",
"method": "POST",
"headers": {
"content-type": "application/x-www-form-urlencoded",
"authorization": "Basic RXhhbXBsZV9BcHBJRDpWUFlndEdXRlRvYVpZSUNTRzhJeVZFV000bUZicGpsU2t4RlRRbzlySkRGZDdzckc=",
"cache-control": "no-cache"
},
"data": {
"client_secret": "MYSECRET",
"grant_type": "authorization_code",
"redirect_uri": "http://localhost/callback",
"code": "bngM6aV5cYHAvhv7wLAM5QSWFDARn7",
"client_id": "MYCLIENTID"
}
}
$.ajax(settings).done(function (response) {
console.log(response);
});
From ajax post above, I have tried to use the "code" from callback, but I've got an error message:
500 Error: Failed to establish a backside connection
I've got stuck here and don't know how to get user profile from SSO.
With in the SSO Service there are some inbuilt macros that can be used to get the user name, for more information please see.
https://console.bluemix.net/docs/services/SingleSignOn/customizing_pages.html#customizing_pages
#USERNAME# The user ID of the authenticated user.

How to use gmail api's in chrome extension?

I am new to chrome extensions and gmail api's.
I am trying to connect with gmail api's while implementation of my extension.
I have api keys and client id.
In your manifest you first need to add :
"background": {
"scripts": ["background.js" ,"client.js"]
},
"content_security_policy": "script-src https://*.google.com 'unsafe-eval'; object-src 'self'",
"oauth2": {
"client_id": "<your client id>",
"scopes": [
scope: 'https://mail.google.com/'
]
},
"permissions": [
"background",
"identity",
"tabs",
"https://www.googleapis.com/*",
"https://*.googleusercontent.com/*",
"https://mail.google.com/",
],
When client.js is the gmail API library ...
Now in your background page you need to connect..I give you example in JS:
chrome.identity.getAuthToken(
{'interactive': true},
function(token){
/// you can use the token( user token ) for create http request to gmail api
}
);
window.gapi_onload = function(){
gapi.client.setApiKey("<your api code>");
gapi.auth.authorize(
{
client_id: '<Your client id>',
immediate: true,
scope: "https://mail.google.com/",
},
function(){
gapi.client.load('gmail', 'v1', gmailAPILoaded);
}
);
}
function gmailAPILoaded(){
// Do things you want with gapi.client
}
Most of things I give you based on this guide but it's not work for me exectly so I change some things.
Good luck
You do not necessarily need the gapi.auth.authorize(...) calls. Look for the chrome.identity API instead.

Resources