EDIT: This issue turns out to have been user error, the passwords had been changed, so the hash was never going to match
I'm using a simple authentication in Spring 4.2.2's toolkit, using a DAO which reads a (Postgres) database table for user's name, password, and authorities
#EnableWebSecurity
#Configuration
class X extends WebSecurityConfigurerAdapter{
...
#Autowired
private SessionRegistry sessionRegistry;
#Autowired
private SessionAuthenticationStrategy sessionAuthenticationStrategy;
#Override
protected void configure(HttpSecurity http){
http.sessionManagement().sessionAuthenticationStrategy(sessionAuthenticationStrategy).maximumSessions(1).sessionRegistry(sessionRegistry).expiredUrl("/login.jsp");
//presumably unrelated additional code related to matchers, roles, https
}
#Bean
public SessionRegistry sessionRegistry(){
return new SessionRegistryImpl();
}
#Bean
public SessionAuthenticationStrategy sessionAuthenticationStrategy(){
return new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry);
}
#Bean
public PasswordEncoder passwordEncoder(){
return new StandardPasswordEncoder();
}
...
}
Recently I restored an old copy of the database, the old database comes from a Redhat 6 server, the new one is CentOS 7, though realistically since this is all database backed, it shouldn't matter. The authentication portion of our code hasn't changed at all, but since I restored the database despite entering the correct credentials I get
BadCredentialsException: Bad credentials at
org.springframework.security.authentication.dao.DaoAuthenticationProvider.additionalAuthenticationChecks(DaoAuthenticationProvider.java:98) at
org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:165) at org.springframework.security.authentication.ProvideManager.authenticate(ProviderManager.java:167) at
....
The rest of the stack trace is all more standard spring/catalina/java bits of the stack trace, nothing custom.
It's not expired, I've deleted cookies, it's not disabled....
This code hasn't changed in literal years neither have the backing database tables or Spring libraries. Debugging I can confirm that the correct user is retrieved by username as it goes towards authentication that the user object is correctly constructed with the password hash and authorities. Since so much of this is done by the default behavior of Spring classes, I can't step through very much of the code as it happens so it's very difficult to identify where the actual bad credentials have occurred and what the heck might have changed.
Googling around, I find many users have problems, but almost of them deal with initial bad configuration. This isn't such a problem, since this code used to work.
Are there any known gotchas related to Spring security that I might test?
Failing that, how can I triage this further?
Some more things to try:
Verify that the database collation and character-set matches across both old and new environments
Do you have a way within your application (or could you write some simple code to) reset a password then try and login with the newly-reset password (or just write some quick code to generate a new one that you know is correct and then set it directly against the database)? If that works, have a look at the format of the new password against the others in the database.
Wire in your own custom DaoAuthenticationProvider that enables you to set a breakpoint (or just logs to the console/file) the generated vs. database password hash
Implement your own custom StandardPasswordEncoder (from here), but again add more logging/breakpoints
I have an application where single user can work in contexts of multiple companies. We call such a connection (user<->company) a permit. Every one of this permits can have different sets of permissions/roles. We want user to login just once and then he can simply change permits within application without need to enter password again.
Till now we had only one application and kept this whole permission model in our own DB. Unfortunately now we have to support second application which should inherit those permits. I was wondering wether is possible to move that model to keycloak so we don't have to replicate it to every single db and keep it in sync manually.
I have searched keycloak documentation regarding this topic but have found no information att all, which seems quite odd, because I don't think we are the first one working with multiple context application.
So now I'm asking is it possible to configure our model in keycloak and if so, how to do it? Eventually are there different options? I guess that I can provided that model as a claim with json structure but that doesn't feel right to me. I was thinking about custom IDP which could provide such claims based on DB so there no spelling errors and less repetition but I feel there should be a better way.
You could try to write your own Keycloak provider (SPI). There is a built in mechanism that allows you to expose REST endpoint on the Keycloak: https://github.com/keycloak/keycloak/tree/master/examples/providers/domain-extension
That REST could be called with authorized context only for example by passing Access-Token (Authorization header with Bearer value). On the provider level (through implementation of: org.keycloak.services.resource.RealmResourceProviderFactory and org.keycloak.services.resource.RealmResourceProvider) you have access to user's Keycloak session and object UserModel like in the following code:
AuthenticationManager.AuthResult authResult = new AppAuthManager().authenticateBearerToken(keycloakSession, keycloakSession.getContext().getRealm());
UserModel userModel = authResult.getUser();
UserModel class has methods for getting and setting attributes, so some information that indicates the current permit/company ID can be stored there. You can use REST methods exposed on the Keycloak to modify the model within the 'session' (represented by Access-Token).
The Github example shows also how to use another Keycloak provider (ex. built-in JPA provider) from you custom provider's level, so using that approach you could try to connect to the database with your permits/company informations. Of course the datasource representing you database should also be registered as Keycloak datasource.
We have a java web app, which contains a lot of wars. We have an Oauth2 server(written by us) and we will have a lot clients( around 8). All of this will be under the same domain. Except of this we have another app( running on completely different tomcat. There a Liferay is used). The idea is that that the user will use them as they are using one app and they should not see big difference.
This is way now what I need is that when I log out from one place in some way to say the oauth2 server and all other clients to log out, too.
Because for client should be : I already logged out why in some parts I'm still logged in?
Currently I'm not sure how to do it.
And to a lot of places I read that normally this is not the practice.
Can you give me hints and explain me from where I can start? Maybe to use Oauth2 in my case in not the best choice?
For your requirement, you can implement OAuth2 using JDBC Token Store from Spring Security. For this to work once user logs out, all client should invoke your Delete token API where you can remove the Access Token
#FrameworkEndpoint
public class RevokeTokenEndpoint {
#Resource(name = "tokenServices")
ConsumerTokenServices tokenServices;
#RequestMapping(method = RequestMethod.DELETE, value = "/oauth/token")
#ResponseBody
public void revokeToken(HttpServletRequest request) {
//Delete the Token
}
}
Also, you should delete the refresh token.This way, the token would be invalidated once user logs-out and subsequent client can no longer use the same token
I'm using spring security to implement a programmatic, manual user login. I have a scenario where I have positively established the user's identity, and wish to log them in. I don't know their password, and so can't use the regular login code path where you submit a form to a url, which spring intercepts via a servlet Filter, doing all of it's auth+session magic.
I've searched, and it seems most people create their own Authentication object, and then tell spring about via:
PreAuthenticatedAuthenticationToken authentication = new PreAuthenticatedAuthenticationToken(user, "", user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);
Indeed, this works. Spring even puts it into the session for me, making subsequent http requests maintain their auth status.
However, I feel like this is a dirty hack. I'll present some details that I hope will give concrete examples of the problems associated with using setAuthentication() inside a controller to achieve a manual login:
To give an idea, my config is:
httpSecurity
.authorizeRequests()
.antMatchers("/test/**").permitAll()
.antMatchers("/admin/**", "/api/admin/**").hasRole("USER_SUPER_ADMIN")
.and()
.formLogin()
.loginPage("/sign-in?sp")
.loginProcessingUrl("/api/auth/sign-in")
.successHandler(createLoginSuccessHandler())
.failureHandler(createLoginFailureHandler())
.permitAll()
.and()
.logout()
.logoutUrl("/api/auth/sign-out")
.logoutSuccessHandler(createLogoutSuccessHandler())
.and()
.sessionManagement()
.maximumSessions(1)
.maxSessionsPreventsLogin(true)
.sessionRegistry(sessionRegistry)
;
Key points in the above config:
I use custom success and failure handlers for the form login
I want to config behavior for max concurrent sessions per user
I want to maintain spring's default session fixation protection (changing session id upon login).
I want to use a session registry
... more of these session/login functionalities, had I chosen to config it.
I stepped through the code to see how spring processes a form login. As expected, Spring does all the session/login functionalities that my HttpSecurity config told it to do when I use the form login. But, when I do my own custom/manual login via SecurityContextHolder.getContext().setAuthentication(), it does NONE of those functionalities. This is because spring does all of it's session/login functionalities stuff inside of a servlet Filter, and my programmatic code can't really call a Filter. Now, I can attempt to add the missing functionalities myself, duplicating their code: I see that the spring Filter uses: ConcurrentSessionControlAuthenticationStrategy, ChangeSessionIdAuthenticationStrategy, and RegisterSessionAuthenticationStrategy. I can create these objects myself, configure them, and call them after my custom login. But, that's really lame to duplicate all that spring code. Furthermore, there's still other behaviors I'm missing - I noticed that when using the form login code path, that spring triggers some login events which don't get triggered when I do my custom login. And there's probably other stuff that I'm missing or don't understand. The whole process is pretty complicated, and I feel like there's a high chance of introducing bugs if this isn't done right, not to mention that library updates would be a pain if I started duplicating spring code.
So, I feel like I'm approaching this from the wrong way. Should I be using a different strategy, so that I'm not bypassing so much of the stuff that spring does for me? Maybe I should try to make my own AuthenticationProvider to accomplish this custom login?
*To clarify, my code more or less works. But, I feel like I accomplished it using a poor strategy because I had to write code duplicating a lot of stuff that spring does for me. Further, my code doesn't perfectly replicate what spring does, making me wonder what negative implications might result. There must be a better way to programatically achieve login.
I wanted to elaborate on how I implemented the advice of dur. In my scenario, I only used a custom AuthenticationProvider.
Instead of creating a custom servlet Filter, such as extending AbstractAuthenticationProcessingFilter, which seemed like a lot of work, I choose to instead use the following strategy:
At the point in my code where I was confident that I had identified the user, and wanted them to be "logged in", I stuck a flag in the user's session, marking that they should be logged in on the next request, along with any other identity/bookkeeping info I needed, such as their username.
Then, I told the browser client to make an http post to the loginProcessingUrl (the same one I configured spring security to use for form-based login), telling them to send the standard username and password form params, although they don't need to send real values - dummy values like foo are fine.
When the user makes that post request (eg to /login), spring will invoke my custom AuthenticationProvider, which will look in the user's session to check for the flag, and to gather the username. Then it will create and return an Authentication object, such as PreAuthenticatedAuthenticationToken, which identifies the user.
Spring will handle the rest. The user is now logged in.
By doing it this way, you stay within the "normal" way of doing logins, and so spring will still automatically:
Call any custom success and failure handlers you configured for the form login, which is nice if you use that place to do certain things on login, like query or update a db.
It will respect any max concurrent sessions per user settings that you may be using.
You get to keep spring's default session fixation attack protection (changing session id upon login).
If you set a custom session timeout, eg via server.session.timeout in a properties file, spring will use it. There's probably other session config attributes that are done at this time too.
If you enabled spring's "remember me" functionality, it will work.
It will fire a login event, which is used for other spring components, such as storing the user's session in a SessionRegistry. I think the events are also used by other parts of spring, such as the actuator, and for auditing.
When I first tried just doing the typically recommended SecurityContextHolder.getContext().setAuthentication(authentication) to login my user, instead of the custom AuthenticationProvider, none of the above bullets were done for me, which can utterly break your app... or cause subtle security bugs - neither are good.
Here's some code to help solidify what I said:
Custom AuthenticationProvider
#Component
public class AccountVerificationAuthenticationProvider implements AuthenticationProvider {
#Autowired
private AppAuthenticatedUserService appAuthenticatedUserService;
#Autowired
private AuthService authService;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// This will look in the user's session to get their username, and to make sure the flag is set to allow login without password on this request.
UserAccount userAccount = authService.getUserAccountFromRecentAccountVerificationProcess();
if (userAccount == null) {
// Tell spring we can't process this AuthenticationProvider obj.
// Spring will continue, and try another AuthenticationProvider, if it can.
return null;
}
// A service to create a custom UserDetails object for this user.
UserDetails appAuthenticatedUser = appAuthenticatedUserService.create(userAccount.getEmail(), "", true);
PreAuthenticatedAuthenticationToken authenticationToken = new PreAuthenticatedAuthenticationToken(appAuthenticatedUser, "", appAuthenticatedUser.getAuthorities());
authenticationToken.setAuthenticated(true);
return authenticationToken;
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
Config spring security to use the provider
// In your WebSecurityConfigurerAdapter
#Configuration
#EnableWebSecurity
public class AppLoginConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AccountVerificationAuthenticationProvider accountVerificationAuthenticationProvider;
#Autowired
private ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider;
#Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
// Spring will try these auth providers in the order we register them.
// We do the accountVerificationAuthenticationProvider provider first, since it doesn't need to do any slow IO to check,
// so it's very fast. Only if this AuthenticationProvider rejects (which means this http request is not for programmatic login), will spring then try the next AuthenticationProvider in the list.
authenticationManagerBuilder
.authenticationProvider(accountVerificationAuthenticationProvider)
// I'm using ActiveDirectory / LDAP for when a user logs in via entering a user + password via the html form, but whatever you want to use here should work.
.authenticationProvider(activeDirectoryLdapAuthenticationProvider);
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
...
}
}
For custom web authentication you should implement combination of a custom authentication filter (for example AbstractAuthenticationProcessingFilter or just GenericFilterBean), a custom authentication provider (AuthenticationProvider) or/and custom authentication token (AbstractAuthenticationToken).
For example, see source of Spring Security Kerberos.
See also:
The AuthenticationManager, ProviderManager and AuthenticationProvider
I would like to ask if there is a point to secure the methods which I call in a REST Controller with Pre and Post annotations. I have configured a security through java configuration like this:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.and()
.formLogin()
(...)
.and()
.authorizeRequests()
.antMatchers("/api/**").hasAuthority("ROLE_USER");
}
So every request under /api should be authorized with ROLE_USER. I tried to find some information about this in the internet but the only thing i could find was this:
https://coderanch.com/t/549265/Spring/method-security-spring-security
However I really can't think of a use case where a hacker would access somehow the methods in the service layer.
URL security and method security in service layer aims at different use cases.
If all you need is control that only users with a certain role can call URL with a given prefix (here API) URL security is what you need full stop.
If you have a complex application where some service methods can be called from different controllers and you want to make sure that you did not fail to restrict an access, method security can come to help by ensuring that only valid users can do certain business actions.
If you have a complex security model, for example several officse with one manager in each that has read and/or write access to his own employees data, method security on service layer directly using business model objects is the way to go.
BTW, using method security in a controller or even worse on a rest controller is generally design smell: if you can do it inside a controller it is generally better to use URL security. If it seems to make sense, you probably have imported business logic into a Fat Ugly Controller. Not speaking about method security being implemented with Spring AOP using by default JDK proxies, when controllers generally do not implement interfaces.
In addition to making it possible to have some kinds of functionality, using both techniques gives an additional layer of security.
Method level security is used to authorize the user. Spring security performs two basic operations before allowing the access.
Authenticate (Who is the user)
Authorize (What authorities the user has)
so for example if the user is having an authority of ROLE_USER and later in the architecture you decide to have rights assigned to some of the roles.
for example let's consider a role 'ROLE_USER'
and following rights has been assigned to the USER
CAN_VIEW_DATA
CAN_ADD_SUB_USERS
and so on.
so when some of the users have the right of CAN_ADD_SUB_USERS and some dont, then the method level security comes in handy.
Of course you have to play with the spring configurations for the rights and authority. But Once configured it provides an extra level of security that the applicaton might need.
Refer to this link for more info http://www.baeldung.com/role-and-privilege-for-spring-security-registration
REST is stateless. You should send something like access token (like Google API) with every request:
https://{server}/api/customers?access_token=BGhznFGDS
You can also send this information via Header-Attribute. The validation layer (Filter) decides whether the controller method may be called or not.
I prefer to implement my own Filters to get 100% of control.