How to implement custom authentication in Spring Security 3? - spring-mvc

I know this has been answered so many times, but I am confused. I already have an Authentication mechanism in my application and I just want to use the authorization part of Spring MVC. I'm using Spring MVC 3 and Spring Security 3.
When I search on internet I found two solutions, the first one is to just implement AuthenticationProvider interface. Example1. The second one is to implement UserDetails and UserDetailsService, Example2 so I'm lost here.
----Update----
The second part of the Question is here. And the solution to the workaround.

In most cases when only using usernames and passwords for authentications and roles for authorisation, implementing your own UserDetailsService is enough.
The flow of the username password authentication is then generally as follows:
A spring security filter (basic authentication/form/..) picks up the username and password, turns it into an UsernamePasswordAuthentication object and passes it on to the AuthenticationManager
The authentication manager looks for a candidate provider which can handle UsernamePasswordtokens, which in this case is the DaoAuthenticationProvider and passes the token along for authentication
The authentication provider invokes the method loadUserByUsername interface and throws either a UsernameNotFound exception if the user is not present or returns a UserDetails object, which contains a username, password and authorities.
The Authentication provider then compares the passwords of the provided UsernamePasswordToken and UserDetails object. (it can also handle password hashes via PasswordEncoders) If it doesn't match then the authentication fails. If it matches it registers the user details object and passes it on to the AccessDecisionManager, which performs the Authorization part.
So if the verification in the DaoAuthenticationProvider suits your needs. Then you'll only have to implement your own UserDetailsService and tweak the verification of the DaoAuthenticationProvider.
An example for the UserDetailsService using spring 3.1 is as follows:
Spring XML:
<security:authentication-manager>
<security:authentication-provider user-service-ref="myUserDetailsService" />
</security:authentication-manager>
<bean name="myUserDetailsService" class="x.y.MyUserDetailsService" />
UserDetailsService Implementation:
public MyUserDetailsService implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//Retrieve the user from wherever you store it, e.g. a database
MyUserClass user = ...;
if (user == null) {
throw new UsernameNotFoundException("Invalid username/password.");
}
Collection<? extends GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("Role1","role2","role3");
return new User(user.getUsername(), user.getPassword(), authorities);
}
}

Related

spring-boot security identify by token

I got an app and I wanna create a connection to my rest-api.
Each user will get a "token" which will automatically be refreshed by google and co. In my requests, I will send the token and if it can be resolved to the user, the request should be answered, else if it is not up to date, I just wanna drop the request and return an error.
Are there still some possibilities?
Thanks for your help!
Current starting:
https://gist.github.com/PascalKu/97bca9506ad4f31c9e13f8fe8973d75b
You need to implement custom authentication in spring. I did the same thing but I had a db like:
fb_email_address | user_id | other_fields...
You must create these classes:
#Component
class TokenAuthenticationFilter extends OncePerRequestFilter {
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain) {
String theToken = request.getParameter('theToken');
TokenAuthentication tokenAuth = new TokenAuthentication(theToken)
SecurityContextHolder.getContext().setAuthentication(tokenAuth)
}
}
You need to add the authentication provider to spring's security system:
#Configuration
#EnableWebSecurity
class WebConfigHolder extends WebSecurityConfigurerAdapter implements WebMvcConfigurer {
#Autowired private TokenAuthenticationProvider tokenAuthenticationProvider
#Override
#Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(tokenAuthenticationProvider)
}
}
Implement authentication provider which actually checks to see if the token is valid.
#Component
class TokenAuthenticationProvider implements AuthenticationProvider {
//called by provider manager at some point during execution of security filters, I think
//it's the security api's job to call this
//the fbauthentication we create in our fbauthenticationfilter gets passed into this
#Override
#Transactional
Authentication authenticate(Authentication auth) {
TokenAuthentication tokenAuthentication = (TokenAuthentication) auth;
String theToken = auth.getThetoken();
boolean theTokenIsInDB = ///CHECK TO SEE IF TOKEN IS IN DB
if(theTokenIsInDB) {
TokenAuthentication t = new TokenAuthentication();
t.setAuthenticated(true);
return t;
} else {
throw new BadCredentialsException("Could not find user");
}
}
#Override
boolean supports(Class<?> authentication) {
boolean ret = TokenAuthentication.isAssignableFrom(authentication)
return TokenAuthentication.isAssignableFrom(authentication)
}
}
You need a simple Authentication Class that is just the object that's used to store the credentials while spring is waiting for the thread to get to the spring security filter; once it gets to that filter it passes authentication objects to the providers that support them. This allows you to have multiple authentication methods like FB, Google, custom tokens, etc... In my app I use FB tokens and in my provider, I check to see if the FB token corresponds to an authorized email address on my whitelist of email addresses. If it does, the user gets access to my app.
public class TokenAuthentication extends Authentication{
String token;
boolean isAuthenticated = false;
public TokenAuthentication(String theToken) { this.token = theToken;}
//getters and setters
}
What this code all does is, whenever someone accesses your API such as /api/person/get?theToken=132x8591dkkad8FjajamM9
The filter you created is run on every request. It checks to see if theToken was passed in and adds the TokenAuthentication to spring security.
At some point in the filter chain, spring security filter will run, and it will see that a TokenAuthentication has been created, and will search for a provider that can perform authentication on that. That happens to be your TokenAuthenticationProvider.
TokenAuthenticationProvider does the actual authentication. If it returns an authentication object that has isAuthenticated set to true, then the user will be allowed to access that api call.
Once authenticated, a user doesn't need to pass theToken again until his cookies are cleared or you invalidate his session. So he can call /api/person without the query parameters for the rest of his interactions. That's because the authentication is stored as a session-scoped data in spring.
Hope that helps. Let me know if anything's missing.

Get Current Principal as my Custom Application User in ASP.Net Core Identity

In previous versions of ASP.NET, if I wanted to have a custom class as my current logged in user, what I did was: I let the FormsAuthentication module do its work, and then, in the PostAuthenticateRequest event I replaced the current Principal (HttpContext.Current.User) with my custom principal object that I fetched from the database (with some caching for performance).
How can I achieve the same in ASP.NET Identity? I have my own ApplicationUser (not the default that comes with the EntityFramework ASP.NET Identity) and my own UserStore.
In every authenticated request, I have the HttpContext.User as a ClaimsPrincipal object. Is there a way to replace that with my CustomClaimsPrincipal?
Is there another, better way, to retrieve the current ApplicationUser instance based on the current ClaimsPrincipal?
If you have your own IUserStore you can implement IUserClaimStore to customize the claims identity which is passed to the claims principal.
If you need to replace the default claims principal you should implement the IUserClaimsPrincipalFactory and pass your implementation to the SignInManager and register the configured manager to your owin context.
It should look like this along the lines.
(Assuming you are using ASP.NET Core Identity, for Identity v2 the interfaces and constructors may differ!)
class CustomClaimsFactory<TUser> : Microsoft.AspNetCore.Identity.IUserClaimsPrincipalFactory<TUser>
where TUser : class
{
public Task<ClaimsPrincipal> CreateAsync(TUser user)
{
// create and return your custom principal
}
}
class OwinStartup
{
public void Configuration(IAppBuilder app)
{
app.CreatePerOwinContext(CreateSignInManager);
}
Microsoft.AspNetCore.Identity.SignInManager CreateSignInManager()
{
UserManager manager; // the manager that uses your custom IUserStore
IHttpContextAccessor accessor; // I don't know where to get it from...
var factory = new CustomClaimsFactory();
return new SignInManager(manager, accessor, factory, null, null, null);
}
}
For ASP.Net Core the OWIN-like startup configuration is done via dependency injection.

How to prevent sensitive fields updated by client

For example, in an web appliation, I have a user model:
class User{
String username;
String email;
String passowrd;
boolean active;
Set<Role> roles;
}
The following operations are supported:
1 guest can register(create a new user)
2 user can upate its info
3 user with role of admin can set the `active` and `roles`
At the server side we use the SpringMVC to get the model User directly:
#RequestMapping(value = "", method = RequestMethod.POST)
protected Result create(#Valid #RequestBody User user, BindingResult bindingResult) {
.....
}
So far so good with normal workflow, but think about someone(not admin user) send that:
/user HTTP/Update
{
"username":"jk",
"active":true,
"roles":[{
id:"role_admin_id"
}]
}
If this requset is accepted, the user jk will have the role of super_admin, which is not expected.
How do you protect that?
First of all, #RequestBody User user you sent is just a regular object you wanna update. It's not Spring Security User. If you want to define User as in spring security user, you' ll have to implements UserDetails. Do you already have spring security setup correctly? I don't know if you use xml or java configuration. If you use java configuration, you can control the access by roles as follow:
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/resources/**", "/signup", "/about").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
.anyRequest().authenticated()
.and()
// ...
.formLogin();
}
Reference: http://docs.spring.io/spring-security/site/docs/current/reference/html/jc.html#authorize-requests

JAAS Custom Login Module with Wildfly

I'm trying to develop a custom JAAS login module, which consumes a token and get's the user data from different sources.
It should work as an authentication realm for wildfly 8.2.1 final. I've got a test servlet in which I want to authenticate so the allowed roles for a injected EJB is checked.
The test from this site: http://www.radcortez.com/custom-principal-and-loginmodule-for-wildfly/ In fact I even started with his git project.
Because I only use a token, I can not use request.login(username, password) to initiate the wildfly login process. So I tried this:
#Inject
private SampleEJB sampleEJB;
...
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String token = request.getParameter("token");
try{
context = new LoginContext("TokenLoginDomain", new TokenCallbackHandler(token));
context.login();
}catch(Exception e){
e.printStackTrace();
}
response.getWriter().println("username=" + exampleEJB.getPrincipalName());
}
My EJB looks like this:
#Stateless
public class SampleEJB {
#Resource
private EJBContext ejbContext;
#RolesAllowed("partner")
public String getPrincipalName() {
return ejbContext.getCallerPrincipal().getName();
}
}
How do I start the login process without credentials in a servlet, so the user is logged in as wildfly user?
You can't authenticate that way in Java EE. With the given code you'll only be authenticated within the LoginContext instance.
As you already found out request.login(username, password) triggers the authentication process, but it's limited to the username/password credential.
In this case you should not only write a custom LoginModule (identity store), but a custom authentication mechanism as well. Authentication mechanisms are the controllers so to speak in the authentication process, while the identity store is the model.
Custom authentication mechanisms can be added via the JASPIC SPI, which WildFly supports well.
You can register a ServerAuthModule (SAM) from the app with some utility code that you can copy from here: https://github.com/arjantijms/glassfish-sam-ee-namespaces/tree/master/src/main/java/javax/security/authenticationmechanism
Then actually register the SAM with code as shown here:
https://github.com/arjantijms/glassfish-sam-ee-namespaces/blob/master/src/main/java/test/SamAutoRegistrationListener.java

How to Customize ASP.NET Web API AuthorizeAttribute for Unusual Requirements

I am inheriting from System.Web.Http.AuthorizeAttribute to create a custom authorization/authentication routine to meet some unusual requirements for a web application developed using ASP.NET MVC 4. This adds security to the Web API used for Ajax calls from the web client. The requirements are:
The user must logon each time they perform a transaction to verify
someone else has not walked up to the workstation after someone has
logged on and walked away.
Roles cannot be assigned to the web service methods at program time.
They must be assigned at run time so that an administrator can
configure this. This information is stored in the system database.
The web client is a single page application (SPA) so the typical forms authentication does not work so well, but I am trying reuse as much of the ASP.NET security framework as I can to meet the requirements. The customized AuthorizeAttribute works great for requirement 2 on determining what roles are associated with a web service method. I accept three parameters, application name, resource name and operation to determine which roles are associated with a method.
public class DoThisController : ApiController
{
[Authorize(Application = "MyApp", Resource = "DoThis", Operation = "read")]
public string GetData()
{
return "We did this.";
}
}
I override the OnAuthorization method to get the roles and authenticate the user. Since the user has to be authenticated for each transaction I reduce the back and forth chatter by performing authentication and authorization in the same step. I get the users credentials from the web client by using basic authentication which passes the encrypted credentials in the HTTP header. So my OnAuthorization method looks like this:
public override void OnAuthorization(HttpActionContext actionContext)
{
string username;
string password;
if (GetUserNameAndPassword(actionContext, out username, out password))
{
if (Membership.ValidateUser(username, password))
{
FormsAuthentication.SetAuthCookie(username, false);
base.Roles = GetResourceOperationRoles();
}
else
{
FormsAuthentication.SignOut();
base.Roles = "";
}
}
else
{
FormsAuthentication.SignOut();
base.Roles = "";
}
base.OnAuthorization(actionContext);
}
GetUserNameAndPassword retrieves the credentials from the HTTP header. I then use the Membership.ValidateUser to validate the credentials. I have a custom membership provider and role provider plugged in to hit a custom database. If the user is authenticated I then retrieve the roles for the resource and operation. From there I use the base OnAuthorization to complete the authorization process. Here is where it breaks down.
If the user is authenticated I use the standard forms authentication methods to log the user in (FormsAuthentication.SetAuthCookie) and if they fail I log them out (FormsAuthentication.SignOut). But the problem seems to be that base OnAuthorization class does not have access to Principal that is updated so that IsAuthenticated is set to the correct value. It is always one step behind. And my guess is that it is using some cached value that does not get updated until there is a round trip to the web client.
So all of this leads up to my specific question which is, is there another way to set IsAuthenticated to the correct value for the current Principal without using cookies? It seems to me that cookies do not really apply in this specific scenario where I have to authenticate every time. The reason I know IsAuthenticated is not set to the correct value is I also override the HandleUnauthorizedRequest method to this:
protected override void HandleUnauthorizedRequest(HttpActionContext filterContext)
{
if (((System.Web.HttpContext.Current.User).Identity).IsAuthenticated)
{
filterContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}
This allows me to return a status code of Forbidden to the web client if the failure was because of authorization instead of authentication and it can respond accordingly.
So what is the proper way to set IsAuthenticated for the current Principle in this scenario?
The best solution for my scenario appears to be bypass the base OnAuthorization completely. Since I have to authenticate each time cookies and caching the principle are not of much use. So here is the solution I came up with:
public override void OnAuthorization(HttpActionContext actionContext)
{
string username;
string password;
if (GetUserNameAndPassword(actionContext, out username, out password))
{
if (Membership.ValidateUser(username, password))
{
if (!isUserAuthorized(username))
actionContext.Response =
new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
}
else
{
actionContext.Response =
new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
}
}
else
{
actionContext.Response =
new HttpResponseMessage(System.Net.HttpStatusCode.BadRequest);
}
}
I developed my own method for validating the roles called isUserAuthorized and I am not using the base OnAuthorization any more since it checks the current Principle to see if it isAuthenticated. IsAuthenticated only allows gets so I am not sure how else to set it, and I do not seem to need the current Principle. Tested this out and it works fine.
Still interested if anyone has a better solution or can see any issues with this this one.
To add to the already accepted answer: Checking current sourcecode (aspnetwebstack.codeplex.com) for System.Web.Http.AuthorizeAttribute, it looks like the documentation is out of date. Base OnAuthorization() just calls/checks private static SkipAuthorization() (which just checks if AllowAnonymousAttribute is used in context to bypass the rest of the authentication check). Then, if not skipped, OnAuthorization() calls public IsAuthorized() and if that call fails, it then calls protected virtual HandleUnauthorizedRequest(). And that's all it does...
public override void OnAuthorization(HttpActionContext actionContext)
{
if (actionContext == null)
{
throw Error.ArgumentNull("actionContext");
}
if (SkipAuthorization(actionContext))
{
return;
}
if (!IsAuthorized(actionContext))
{
HandleUnauthorizedRequest(actionContext);
}
}
Looking inside IsAuthorized(), that's where Principle is checked against roles and users. So, overriding IsAuthorized() with what you have above instead of OnAuthorization() would be the way to go. Then again, you'd still have to probably override either OnAuthorization() or HandleUnauthorizedRequest() anyway to decide when to return a 401 vs a 403 response.
To add to the absolutely correct answer by Kevin, I'd like to say that I may slightly modify it to leverage the existing .NET framework path for the response object to ensure downstream code in the framework (or other consumers) is not adversely affected by some weird idiosyncrasy that can't be predicted.
Specifically this means using this code:
actionContext.Response = actionContext.ControllerContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, REQUEST_NOT_AUTHORIZED);
rather than:
actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
Where REQUEST_NOT_AUTHORIZED is:
private const string REQUEST_NOT_AUTHORIZED = "Authorization has been denied for this request.";
I pulled that string from the SRResources.RequestNotAuthorized definition in the .NET framework.
Great answer Kevin! I implemented mine the very same way because executing OnAuthorization in the base class made no sense because I was verifying an HTTP Header that was custom to our application and didn't actually want to check the Principal at all because there wasn't one.

Resources