I am using Identity Server 4 to secure an mvc app and all peripheral APIs. During principal creation I'm using the claims transformation middleware, in which I'd like to make a call to a secured API for additional information.
The claims transformation middleware is wired up in the Configure method like so:
app.UseClaimsTransformation(o => new ClaimsTransformer().TransformAsync(o));
And the ClaimsTransformer class looks like:
public async Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context)
{
// meat and potatoes goes here...
return context.Principal;
}
I've tried getting the access token from the ClaimsTransformationContext with the following code within TransformAsync, however this seems to result in an infinite loop back to the TransformAsync method on the ClaimsTransformer class.
var accessToken = context.Context.Authentication.GetTokenAsync("access_token");
Is it possible to retrieve the access token during the .net core claims transformation?
Or is this specific API call something htat shouldn't be done on behalf of the user and better handled one step up and suited for a more server to server approach (client credentials grant)?
I have a webapi backend that several client applications are using. The api is secured with jwt authentication, it is based upon the following example: https://github.com/mrsheepuk/ASPNETSelfCreatedTokenAuthExample. Since I am not yet very comfortable with all the concepts of token based authentication I could use some guidance in this. My issue is that I need my applications to utilize the same api but to limit access for each application to a specific area or controller.
According to the example I can protect methods within an area with:
[Authorize("Api")]
A policy is added in startup with
authOptions.AddPolicy("Api", new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme) // "Bearer" scheme
.RequireAuthenticatedUser().Build());
For secured requests from the client I typically have an angular 2 app that simply adds the jwt in the headers like so:
headers.append('Authorization', 'Bearer ' + jwt);
I don't know of all the mechanics here but I am assuming that when a secure method is requested, the "Api" attribute decoration is what decides/limits which policy is to be used with a certain route in the api.
What is best practice and how do I extend this to work with individually accessible sections?
You can create an ActionFilterAttribute for Authorization and use it on all the actions.
You can implement the FrameworkAuthorise filter methods as per your requirements.
Global.ApiKey is the unique code for your application to identity you have access to that application or not.
[FrameworkAuthorise(Global.ApiKey, AuthorisationType.None)]
public async Task<IHttpActionResult> Get()
{
// code goes here
}
[FrameworkAuthorise(Global.ApiKey, AuthorisationType.Bearer)]
public async Task<IHttpActionResult> Post()
{
// code goes here
}
Net Core policy authorization, however it is looking very static to me. Because in the Enterprise Application, there is an often need for new roles which will need new policies (as far as i understand) or if you want to implement new type of policy specific for certain client. For example if we are building an CMS which will be driven by those policies, we will want, each client to be able to define hes own. So can this new policy base mechanism be more dynamic or, it's idea is entire different?
thanks :))
I always recommend that people take a look # the least privilege repo as it has some great examples of all the various approaches one can take with the new ASP.NET Core Authentication and Authorization paradigms.
Can this new policy base mechanism be more dynamic?
Yes, in fact, it is more dynamic than the previous role-based concepts. It allows you to define policies that can be data-driven. Here is another great resource for details pertaining to this. You can specify that an API entry point for example is protected by a policy (for example), and that policy can have a handler and that handler can do anything it needs to, i.e.; examine the current User in context, compare claims to values in the database, compare roles, anything really. Consider the following:
Define an entry point with the Policy
[Authorize(Policy = "DataDrivenExample")]
public IActionResult GetFooBar()
{
// Omitted for brevity...
}
Add the authorization with the options that add the policy.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddAuthorization(options =>
{
options.AddPolicy("DataDrivenExample",
policy =>
policy.Requirements.Add(new DataDrivenRequirement()));
});
services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();
}
Then define the handler.
public class MinimumAgeHandler : AuthorizationHandler<DataDrivenRequirement>
{
protected override void Handle(
AuthorizationContext context,
DataDrivenRequirement requirement)
{
// Do anything here, interact with DB, User, claims, Roles, etc.
// As long as you set either:
// context.Succeed(requirement);
// context.Fail();
}
}
Is the idea entirely different?
It should feel very similar to the previous concepts that you're accustomed to with auth8 and authz.
The accepted answer is still quite limiting. It doesn't allow for dynamic values at the Controller and Action level. The only place a custom value could be added is in the requirement when the policy is added. Sometimes you need more fine grain control over the authorization process. A very common scenario is permission based security. Each controller and action should be able to specify the permissions required to access them. See my answer here for a more powerful solution that lets you use custom attributes to decorate your controllers and actions with any information you need while doing authorization.
I am already using a custom authentication provider in my ServiceStack based web services application.
I'm overriding the Authenticate method, and validating my user against one of multiple backend tenant databases. I currently determine the tenant database by matching an API key to a database string.
public override object Authenticate(
IServiceBase authService,
IAuthSession session,
Auth request) // <- custom object here, MyCustomAuth request
{
// ...
}
This works when each application is for a single tenant (a tenant/customer can build their own application and use that API key). Moving forward I want to build a multi-tenant mobile application. Thus the API key method cannot be used because I can't expect each user to type it in, hence I can't determine which tenant is using the application.
I wanted to alter the Auth object so that I could include the TenantId (provided by the user on login). However, I can't see how I can customize that object.
Is there anyway to customize that Auth object, or do I have to find an alternative solution?
You can't modify the built-in Authenticate Request DTO used, but you can use its Dictionary<string, string> Meta property to send additional metadata with the Authenticate request, e.g:
client.Post(new Authenticate {
...
Meta = new Dictionary<string,string> {
{"TenantId", tenantId},
}
}
Alternatively you can send additional info in the QueryString or HTTP Headers and access the IRequest with:
var tenantId = authService.Request.QueryString["TenantId"];
I'm trying to integrate Spring Security in my web application. It seems pretty easy to do as long as you integrate the whole process of authentication and authorization.
However, both authentication and authorization seem so coupled that it's being very time-consuming for me to understand how I could split these processes, and get authentication independently of authorization.
The authentication process is external to our system (based on single sign-on) and this cannot be modified. Nevertheless, once the user succeeds this process, it's loaded in the session, including roles.
What we are trying to achieve is to make use of this information for the authorization process of Spring Security, that's to say, to force it to get the roles from the user session instead of picking it up through the authentication-provider.
Is there any way to achieve this?
If your authentication is already done using an SSO service, then you should use one of spring security's pre-authentication filters. Then you can specify a UserDetails service (possibly custom) that will use the pre-authenticated user principle to populate the GrantedAuthority's
SpringSecurity includes several pre-authentication filters including J2eePreAuthenticatedProcessingFilter and RequestHeaderPreAuthenticatedProcessingFilter. If you can't find one that works for you, its also possible, and not that hard to write your own, provided you know where in the request your SSO implementation stuffs the data. (That depends on the implementation of course.)
Just implement the Filter interface and do something like this in the doFilter method:
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// principal is set in here as a header or parameter. you need to find out
// what it's named to extract it
HttpServletRequest req = (HttpServletRequest) request;
if (SecurityContextHolder.getContext().getAuthentication() == null) {
// in here, get your principal, and populate the auth object with
// the right authorities
Authentication auth = doAuthentication(req);
SecurityContextHolder.getContext().setAuthentication(auth);
}
chain.doFilter(request, response);
}
Yes, it's possible. Spring Security (like most of the rest of Spring) is interface-driven so that you can plug in your own implementations selectively for different parts of the framework.
Update: Spring's authorisation and authentication mechanisms work together - the authentication mechanism will authenticate the user and insert various GrantedAuthority instances in the security context. These will then be checked by the authorisation machinery to allow/disallow certain operations.
Use nont's answer for the details on how to use pre-existing authentication. The details of how you get the details from your session (e.g. roles ) will of course depend on your specific setup. But if you put in the GrantedAuthority instances derived from the roles pre-populated in your session by your SSO system, you will be able to use them in your authorisation logic.
From the reference documentation (slightly edited, with my emphasis):
You can (and many users do) write
their own filters or MVC controllers
to provide interoperability with
authentication systems that are not
based on Spring Security. For example,
you might be using Container Managed
Authentication which makes the current
user available from a ThreadLocal or
JNDI location. Or you might work for a
company that has a legacy proprietary
authentication system, which is a
corporate "standard" over which you
have little control. In such
situations it's quite easy to get
Spring Security to work, and still
provide authorization capabilities.
All you need to do is write a filter
(or equivalent) that reads the
third-party user information from a
location, build an Spring
Security-specific Authentication
object, and put it onto the
SecurityContextHolder. It's quite easy
to do this, and it is a
fully-supported integration approach.
The server that handles the authentication should redirect the user to the application passing to it some kind of key (a token in CAS SSO). Then the application use the key to ask to the authentication server the username and roles associated. With this info create a security context that is passed to the authorization manager. This is a very simplified version of a SSO login workflow.
Take a look to CAS SSO and CAS 2 Architecture.
Tell me if you need more information.
we have had the same requirement where we had to use spring security for authorization purpose only. We were using Siteminder for authentication. You can find more details on how to use authorization part of spring security not authentication here at http://codersatwork.wordpress.com/2010/02/13/use-spring-security-for-authorization-only-not-for-authentication/
I have also added source code and test cases at http://code.google.com/p/spring-security-with-authorization-only/source/browse/
I am trying to understand CAS authentication with our own Authorization and was getting confused since the User object in Spring Security always expects the password to be filled in and we don't care about that in our scenario. After reading Surabh's post, it seems that the trick is to return a custom User object without the password filled in. I will try that out and see if it works in my case. Hopefully no other code in the chain will be expecting the Password in the User object.
I use the authorization by this:
Inject the authorization related bean into my own bean:
#Autowired
private AccessDecisionManager accessDecisionManager;
#Autowired
FilterSecurityInterceptor filterSecurityInterceptor;
Use this bean by this:
FilterInvocation fi = new FilterInvocation(rundata.getRequest(), rundata.getResponse(), new FilterChain() {
public void doFilter(ServletRequest arg0, ServletResponse arg1) throws IOException, ServletException {
// TODO Auto-generated method stub
}
});
FilterInvocationDefinitionSource objectDefinitionSource = filterSecurityInterceptor.getObjectDefinitionSource();
ConfigAttributeDefinition attr = objectDefinitionSource.getAttributes(fi);
Authentication authenticated = new Authentication() {
...........
public GrantedAuthority[] getAuthorities() {
GrantedAuthority[] result = new GrantedAuthority[1];
result[0] = new GrantedAuthorityImpl("ROLE_USER");
return result;
}
};
accessDecisionManager.decide(authenticated, fi, attr);
I too did spent lot of hours investigating on how to implement custom authorization without authentication.
The authentication process is external to our system (based on single sign-on).
I have done it, as mentioned below and it Works!!! (I am sure there are many other ways to it better, but this way just suits my scenario well enough)
Scenario : User is already authenticated by external system and all information needed for authorization is present in the request
1.
Security config need to be created, enabling global method security as below.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
class SpringWebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
}
}
2.) Implement Spring PermissionEvaluator to authorize whether the request should be allowed or rejected
#Component
public class CustomPermissionEvaluator implements PermissionEvaluator {
public boolean authorize(final String groups, final String role) {
boolean allowed = false;
System.out.println("Authorizing: " + groups + "...");
if (groups.contains(role)) {
allowed = true;
System.out.println(" authorized!");
}
return allowed;
};
#Override
public boolean hasPermission(final Authentication authentication, final Object groups, final Object role) {
return authorize((String) groups, (String) role);
};
#Override
public boolean hasPermission(final Authentication authentication, final Serializable targetId, final String targetType, final Object permission) {
return authorize((String) targetId, (String) permission);
};
}
3.) Add MethodSecurityConfig
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new CustomPermissionEvaluator());
return expressionHandler;
}
}
4.) Add #PreAuthorize in your controller as shown below. In this example, all the groups of the user are present in request header with key 'availableUserGroups'.
This is then passed on to the CustomPermissionEvaluator to verify authorization. Please note that spring automatically passes Authentication object to the method 'hasPermission'.
So in case if you want to load user and check using spring 'hasRole' method, then this can be used.
#PreAuthorize("hasPermission(#userGroups, 'ADMIN')")
#RequestMapping(value = "/getSomething")
public String getSomething(#RequestHeader(name = "availableUserGroups") final String userGroups) {
return "resource allowed to access";
}
Handling Other Scenarios :
1.) In scenario where you want to load the user before you can perform the authorization. You can use spring pre-authentication filters, and do it in a similar way.
Example link : http://www.learningthegoodstuff.com/2014/12/spring-security-pre-authentication-and.html