At pages I am using tag:
security:authorize ifAnyGranted="ROLE_USER,ROLE_ADMIN"
...
It works.
But at server side: I use SecurityContextHolder.getContext().getAuthentication().isAuthenticated(),it is always true. When I didn't log in, the system take anonymousUser as the log in user.
How can I avoid this?
SecurityContextHolder.getContext().getAuthentication().isAuthenticated() will return true almost always.
use this
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return authentication != null && !(authentication instanceof AnonymousAuthenticationToken) && authentication.isAuthenticated();
If it is spring security 2.x, there is AuthorityUtils.userHasAuthority(String authority) which you can use to make explicit check for the role.
You could iterate over SecurityContextHolder.getContext().getAuthentication().getAuthorities() and ensure you permit operation only for the roles that you want.
Related
I've a oauth2 resource server which uses the JwtBearerMiddleware to validate the access tokens. Now I wan't that the access token is invalid if the security stamp has changed. As it looks like this middleware doesn't validate the security stamp by itself.
I've found the SecurityStampValidator class which only seems to validate cookie authentication.
Where and how do I have to validate the security stamp from my json web token?
My current way to do it is to register an eventhandler for the OnTokenValidated event when I register the JwtBearerMiddleware. In this eventhandler I simply query the database for the security claim and compare it with the one in the token. When the security stamp isn't the same I just set the Ticket and SecurityToken of the context to null and skip to the next middleware which eventually will throw an 401 http status code if authentication is required.
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
...
Events = new JwtBearerEvents
{
OnTokenValidated = async (ctx) =>
{
var securityStampClaim = ctx.Ticket.Principal.Claims.FirstOrDefault(claim => claim.Type == "AspNet.Identity.SecurityStamp");
var subjectClaim = ctx.Ticket.Principal.Claims.FirstOrDefault(claim => claim.Type == OpenIdConnectConstants.Claims.Subject);
if (securityStampClaim == null || subjectClaim == null)
return;
var user = await userStore.FindByIdAsync(subjectClaim.Value, ctx.HttpContext.RequestAborted);
if (user?.SecurityStamp == securityStampClaim.Value)
return;
ctx.SecurityToken = null;
ctx.Ticket = null;
ctx.SkipToNextMiddleware();
}
}
});
Is this how it should be done?
Is this how it should be done?
Technically, yes (you could even use SignInManager.ValidateSecurityStampAsync(principal) to simplify your code a bit).
That said, you should strongly consider avoiding storing the security stamps in your JWT tokens because they are not just "opaque" strings used to determine whether a token or a cookie should be considered as revoked, they are also used as the sole source of entropy by ASP.NET Core Identity to generate 2FA tokens: if you store them as-is in a JWT, they can be easily extracted by a malicious third-party client application and used to predict valid 2FA codes for the logged in user.
This is a known issue, but AFAIK, there's no plan to fix it: https://github.com/aspnet/Identity/issues/626.
If you want to store the security stamps in your access tokens, consider using OpenIddict's default (encrypted) format, which is exactly the same as the one used by ASP.NET Core for its encrypted authentication cookies.
How can I configure Spring SAML to send "assertionConsumerServiceIndex" instead of "assertionConsumerServiceUrl" in the SAML Authentication Requests?
Another question:
Where can I report an issue of the Spring security SAML project?
Thanks
Got it working but not through config file. I found following comment in the Spring SAML source code:
// AssertionConsumerServiceURL + ProtocolBinding is mutually exclusive with AssertionConsumerServiceIndex, we use first one here
I had to modify buildReturnAddress method of WebSSOProfileImpl class as below to insert AssertionConsumerServiceIndex instead of AssertionConsumerServiceURL + ProtocolBinding when creating new AuthNRequest:
if (service != null) {
request.setAssertionConsumerServiceIndex(service.getIndex());
}
Yes, We need to alter the way buildReturnAddress() behaves in f/w. We can do this simply by extending WebSSOProfileImpl and overriding buildReturnAddress() method in our service provider code.
Using spring securiity, I'm faced with a requirement for a complex business decision about whether to allow anonymous access or insist on user login. Logic is too complex for "intercept-url" expressions ( intercept-url pattern='/mypattern/**'...)
E.g. assume a RESTFul books service:
https://myserver/rest/book?title=war_and_peace
https://myserver/rest/book?title=the_firm
Say "war and peace" allows anonymous access because its old and its copyrights have expired.
While "the firm" is copyrighted & requires login (so as to charge the user).
This copyright info is available in a database.
Could anyone please offer any hints as to how to achieve this in spring secuirity? thanks in advance
There are of course multiple ways that code can look like, but to get the idea:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth instanceof AnonymousAuthenticationToken && "the_firm".equals(title)) {
throw new AccessDeniedException("Requires login!");
}
Update: A more declarative way is to use annotations:
#PostAuthorize("hasPermission(returnObject, 'READ')")
public Book findBook(String title) {
// ...
}
This requires that you create a permission evaluator bean and add config:
<global-method-security pre-post-annotations="enabled">
<expression-handler ref="expressionHandler" />
</global-method-security>
#Bean
public DefaultMethodSecurityExpressionHandler expressionHandler() {
DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
handler.setPermissionEvaluator(permissionEvaluator);
return handler;
}
I'd like to use WebSecurity+SimpleMembership, but implement the ability to (optionally) login users via a custom/alternative authentication method.
WebSecurity.Login only has one method signature, which requires both a username and a password. I'd like to skip the password check, e.g.:
if (MyCustomAuthenticationMethod.Authenticate(username, customData)) {
WebSecurity.Login(username); // Login without password check, method doesn't exist though
}
I assume custom-auth-methods are possible given OAuthWebSecurity exists, but I'm not sure how to go about implementing my own.
Well, you could simply go back to root of authentication and call directly
FormsAuthentication.SetAuthCookie
This will create cookie and authenticate your user.
See Asp.net Memebership Authorization without password
They didn't make it easy to login without a password. One method could be to make your own custom OAuth plug-in and simply call it with your own token like this:
OAuthWebSecurity.Login("google", "token", true);
You can find here how to create a custom OAuth provider:
http://www.codeguru.com/columns/experts/implementing-oauth-features-in-asp.net-mvc-4.htm
And you can browse the code here: https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/Microsoft.Web.WebPages.OAuth/OAuthWebSecurity.cs
Here is a snippet from OAuthWebSecurity.cs file that shows the internals of how to user is authenticated without password:
internal static bool LoginCore(HttpContextBase context, string providerName, string providerUserId, bool createPersistentCookie)
{
var provider = GetOAuthClient(providerName);
var securityManager = new OpenAuthSecurityManager(context, provider, OAuthDataProvider);
return securityManager.Login(providerUserId, createPersistentCookie);
}
Perhaps someone out there already made this plugin.
Does Spring Security gives any such API where I can pass username & password and it will return either Authentication Object for successful authentication or AuthenticationCredentialsNotFoundException for unsuccessful authentication?
Let me elaborate my requirements:
Our application has a HTTP API(say, /createXXX.do) and the client is hitting this with username, password & other parameters.
Now I want to authenticate + authorize this access (coming from HTTP Hits to my application).
My planned design is like below:
a) I will not restrict access of my HTTP API context(i.e. /createXXX.do)
b) Once the request reached my doGet()/doPost(), I will retrieve the username & password from request and want to use some spring security API like below:
Authentication validateXXXXX(String username, String password)
throws AuthenticationCredentialsNotFoundException;
c) so that this above API internally push these username/password to the existing spring security chain and return me the Authentication Object for successful authentication or AuthenticationCredentialsNotFoundException for unsuccessful authentication.
d) For unsuccessful authentication, I will catch AuthenticationCredentialsNotFoundException and return the HttpServletResponse with AUTHENTICATION_ERROR code.
e) and for successful authetication, based on authiories from Authentication Object, I will allow or return the HttpServletResponse with AUTHORIZATION_ERROR code.
Can anyone know about such spring security API?
Any pointers/suggestion will be highly appreciated.
Thanks.
If you have just one authentication source (only LDAP or only DB) you can configure some implementation of org.springframework.security.authentication.AuthenticationProvider in your security context. Then you can use it:
User user = new User(login, password, true, true, true, true, new ArrayList<GrantedAuthority>());
Authentication auth = new UsernamePasswordAuthenticationToken(user, password,new ArrayList<GrantedAuthority>());
try {
auth = authenticationProvider.authenticate(auth);
} catch (BadCredentialsException e) {
throw new CustomBadCredentialsException(e.getMessage(), e);
}
// but your need to push authorization object manually
SecurityContext sc = new SecurityContextImpl();
sc.setAuthentication(auth);
SecurityContextHolder.setContext(sc);
It is "low level" manipulation. You can use element from Spring Security namespace. It can provide login controller, even login form for you (and it can handle this situation automatically).