custom AuthorizeAttribute in ASP.NET Core - asp.net-core

I have asp.net core identity server with grpc and a asp.net core api and i what to when user sends a request with jwt token to the asp.net core api the jwt token goes to my custom authorize attribute and in my custom authorize attribute i send the jwt token to my identity server with grpc and at the response identity server give me roles and has access that is true and after that i store roles and token in the redis database so every time if token was in redis no need to send a request to identity server so i don't know how to Handel it should my attribute use Authorization Filter or authorization handler and my grpc server is ready
i request to my grpc service
AuthorizationGrpcServices.ValidateToken(string token)
and the result is this like this
bool access = true
string roles = " Admin , User "
so i need custom attribute that use redis and this grpc service

Related

How to implement an authentication within Blazor Server App with JWT from Web API

I have a Blazor Server app which wants to connect to a .Net Core WebApi. The app should send an authentication request and the WebApi returns a JWT containing user data. For any further communication with the WebApi the JWT should be used to authorize against it.
I'd like to ensure that only authenticated users can access the server app. If someone is not authenticated he or she should be redirected to a login page.
Up to now I've used a combination of default Identity with AzureAD authentication.
Is there any option to have a JWT authentication working the same way?

Where does AuthorizationHandlerContext.User get created in ASP.NET Core?

I have an AuthorizationHandler that evaluates some authorization requirements for policy-based authorization. Some part of ASP.NET Core calls HandleRequirementAsync with an instance of AuthorizationHandlerContext.
Where does AuthorizationHandlerContext.User get populated?
For context, I look up some properties in AuthorizationContext.User that correspond to OAuth2 claims in a JWT access token that is included in the HTTP request. This is working fine when the JWT token was issued by IdentityServer4, but now I am adding support for access tokens to come from a secondary Identity Provider.
When the token is from this other provider, AuthorizationContext.User is a null object containing all-blank fields (i.e. it has none of the claims that are in the access token). This secondary identity provider (and its public key) are included in the JWT Bearer authentication scheme in TokenValidationParameters.ValidIssuers and TokenValidationParameters.IssuerSigningKeys, respectively.
This leads to the following log messages:
AuthenticationScheme: "Bearer" was successfully authenticated.
Authorization failed for user: <sub from the access token used in the request>

How to integrate Social Login with existing .Net core Web API backend and Angular SPA frontend with working OpenIddict user/password and bearer token

TL;DR
Question: how to implement social login (OAuth2 authorization flow) with an existing SPA/Web API application that is based on identity, user/password, bearer token authentication?
I have an existing application that has:
Backend: .Net Core 2 Web API with Identity and OpenIddict services configured, with a working authentication process based on user/password challenge for bearer token.
Users are stored with Identity (AspNetUsers).
Part of the Startup.cs code
// Register the OpenIddict services.
services.AddOpenIddict()
.AddCore(options =>
{
options.UseEntityFrameworkCore().UseDbContext<ApplicationDbContext>();
})
.AddServer(options =>
{
options.UseMvc();
options.EnableTokenEndpoint("/connect/token");
options.AllowPasswordFlow();
options.AllowRefreshTokenFlow();
options.AcceptAnonymousClients();
options.RegisterScopes(
OpenIdConnectConstants.Scopes.OpenId,
OpenIdConnectConstants.Scopes.Email,
OpenIdConnectConstants.Scopes.Phone,
OpenIdConnectConstants.Scopes.Profile,
OpenIdConnectConstants.Scopes.OfflineAccess,
OpenIddictConstants.Scopes.Roles);
})
.AddValidation();
.
Frontend: SPA Angular 7 app that consumes this backend API and token authorization
So basically the current setup is, user inputs user/password to the SPA that invokes the backend /connect/token endpoint that validates the credentials and generates the token for the client.
And now I need to integrate Social Login (OAuth2 Authorization flow) so that
user chooses login with provider,
gets redirected to providers authorization page,
gets redirected back to my application that
needs to create the Identity user and save the Identity UserLoginInfo data and
provide my application token so that the user can login.
I understand the OAuth2 authorization flow that needs to Request an Authorization Code and then Exchange Authorization Code for an Access Token for that provider. I also know that this flow must use backend, once it uses sensitive information like client_secret that can't be stored in client side.
But at some point user needs to interact with frontend, so connecting these parts seems very difficult considering that these are wide used technologies. All practical examples I found on Google were using .Net Core MVC application. I also found this article ASP.NET Core 3.0 Preview 4 - Authentication and authorization for SPAs that seems promising but is still in Preview 4.
I already created the social providers apps and I have client_id, client_secret. Also registered my redirects url's.
What I tried with no success was:
In frontend user chooses login with social provider,
User gets redirected to provider authorization page, authenticates himself and
gets redirected from the provider to my frontend URL (redirect_uri) with the provider's code then
my frontend calls my backend /connect/token existing endpoint passing the selected provider and the received code, the endpoint was programmed to receive the provider and code also, then
my backend calls provider's get AccessToken url posting "grant_type", "authorization_code" "code", code "redirect_uri", "https://same_frontend_host/same/path" "client_id", providerClientId "client_secret", providerSecret and receives a StatusCode: 401, ReasonPhrase: 'Unauthorized' response
What am I doing wrong? It's been a real hard time to get this to work.
What worked but it's not what I need
An implicit 2 step authorization flow using frontend for provider authentication calls and a backend call to get my bearer token and create Identity user. With this setup user made a successful login using a social provider, unfortunately it's not what I need
EDIT:
Made a diagram of what is implemented, it is failing at step 5/6 with StatusCode: 401, ReasonPhrase: 'Unauthorized' and further steps are not completed.
The flow you describe pretty much corresponds to "Authorization Cross Domain Code", an OpenID Connect flow that has never been standardized.
I wouldn't recommend going with such a non-standard option. Instead, consider tweaking your flow to make your JS client exclusively communicate with your own authorization server instead of starting the flow by making the client redirect the user agent to an external provider.
The key idea here is that your own authorization server should initiate the initial communication with the external provider (i.e it should build the authorization request and redirect your users to the external provider's authorization endpoint) and handle the last part: the callback authorization response. For that, I'd recommend going with the OAuth2/OIDC handlers shipping with ASP.NET Core (there are providers for Google, Facebook and many more)
Of course, this doesn't mean your JS client can't send a hint about the external provider the user should use to authenticate. It's something you can easily handle in your authorization controller. Here's an example:
public class AuthorizationController : Controller
{
private readonly IAuthenticationSchemeProvider _authenticationSchemeProvider;
private readonly SignInManager<ApplicationUser> _signInManager;
public AuthorizationController(
IAuthenticationSchemeProvider authenticationSchemeProvider,
SignInManager<ApplicationUser> signInManager)
{
_authenticationSchemeProvider = authenticationSchemeProvider;
_signInManager = signInManager;
}
[HttpGet("~/connect/authorize")]
public async Task<IActionResult> Authorize(OpenIdConnectRequest request)
{
Debug.Assert(request.IsAuthorizationRequest(),
"The OpenIddict binder for ASP.NET Core MVC is not registered. " +
"Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");
if (!User.Identity.IsAuthenticated)
{
// Resolve the optional provider name from the authorization request.
// If no provider is specified, call Challenge() to redirect the user
// to the login page defined in the ASP.NET Core Identity options.
var provider = (string) request.GetParameter("identity_provider");
if (string.IsNullOrEmpty(provider))
{
return Challenge();
}
// Ensure the specified provider is supported.
var schemes = await _authenticationSchemeProvider.GetAllSchemesAsync();
if (!schemes.Any(scheme => scheme.Name == provider))
{
return Challenge();
}
// When using ASP.NET Core Identity and its default AccountController,
// the user must be redirected to the ExternalLoginCallback action
// before being redirected back to the authorization endpoint.
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider,
Url.Action("ExternalLoginCallback", "Account", new
{
ReturnUrl = Request.PathBase + Request.Path + Request.QueryString
}));
return Challenge(properties, provider);
}
// ...
}
}

JWT handling with WSO2-AM

we plan to introduce an API management solution and we're currently setting up a proof of concept with WSO2 AM. We want to use the WSO2 API gateway to check whether a certain consumer application is allowed to use an API and to throttle the request rate.
I work on the identity workflow and I wonder how a consuming application can pass a JWT token to the backend service with WSO2-AM in between.
First, this is our current scenario:
Without API gateway
The consuming application gets a JWT token for its carbon user from an identity provider. The JWT contains some claims about the user, e.g. the roles he/she belongs to.
The app calls the service an passes the JWT token in the Authorization HTTP header like: Authorization: Bearer
The service validates the issuer and signature of the JWT and retrieves the claims from it.
So, this is pretty straight forward. Now we put an API gateway in between the application and the service:
With API gateway
The consuming application gets a JWT token for its carbon user from an identity provider.
The consuming application uses OAuth2 to get an access token for the following API calls. We can use the client_credentials grant type and simply pass the the client id and client secret. I haven't yet tried it, but we could possibly use the JWT grant type (see https://docs.wso2.com/display/ISCONNECTORS/Configuring+JWT+Grant+Type) and use the JWT for passing user information to the API gateway.
The API gateway validates the JWT against the public key of the identity provider when using the JWT grant type.
An access token is returned to the app.
The app sends an API request to the gateway and passes the access token in the Authorization HTTP header.
The gateway validates the access token.
The gateway forwards the API request to the service.
And there is my problem: How can the JWT from 1/2. be passed to the service?
There is a documentation for "Passing Enduser Attributes to the Backend Using JWT" (see https://docs.wso2.com/display/AM210/Passing+Enduser+Attributes+to+the+Backend+Using+JWT), but this would introduce a new JWT, issued and signed by WSO2-AM, and I'm not sure, whether this JWT contains all information from the JWT used to create the access token (or even the original JWT).
Another way I could think of is using a custom HTTP header for passing the JWT through the gateway to the service. I cannot use the Authorization header (as we do without the API gateway), because WSO2-AM expects the access token in that header.
Since I'm not happy with either solutions, I want to ask the experts: How would you solve this?
Thanks,
Torsten
The only possibility I can think of is to send the JWT token in a custom Header for the backend service.

Retrieve id_token based on access_token in API

We are current building a collection of back-end ASP.NET Core microservices. These services will not be accessed directly from the front-end application, but rather accessed through an ASP.NET Core API gateway. We are using IdentityServer4 for the OpenID Connect server. I have been able to setup the UseJwtBearerAuthentication middleware to have API gateway validate the JWT bearer token (access_token) against IdentityServer4. I would like to be able to have the API gateway inject the id_token, based on the access_token, into the requests made to the back-end services that may need to know the end-user.
Is there a way to configure the JWT middleware to retrieve the id_token when validation the access_token or do I need to manually call the OpenID Connect server in the API gateway?
You don't use id_tokens at APIs - they are for clients.
If you want to have access to certain identity claims, either include them in the access token (by configuring the ScopeClaims on the resource scope), or use the access token to contact the userinfo endoint which in turn will return the identity claims.
The JWT middleware performs standalone verification, it does not contact the identity server to verify or retrieve anything. You'll have to make an additional call.