I am currently using the grails and Spring security to implement the authenitcation. Not doing much customization , using the out of the box
and everything works fine for a user who lands into the auth.gsp where he will enter the username/password.
Now i have a requirement along with the normal flow, there will be a punch out from external site to our site.punch out will have username and passord provided as parameters.
In the punch out scenario user should not see the login screen and should get authenticated using the username/password provided in the url parameter.
Is this possible ?
How can I acheive both this in the same code
Yes, you can do programmatic login. For example:
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.context.SecurityContextHolder;
....
AuthenticationManager authenticationManager;
....
def login(String username, String password) {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(params.username, params.password);
User details = new User(params.username);
token.setDetails(details);
try {
//doing actual authentication
Authentication auth = authenticationManager.authenticate(token);
log.debug("Login succeeded!");
//setting principal in context
SecurityContextHolder.getContext().setAuthentication(auth);
return true
} catch (BadCredentialsException e) {
log.debug("Login failed")
return false
}
}
You can see some example here: http://raibledesigns.com/rd/entry/java_web_application_security_part3
Hope this helps.
Related
I am using latest Grails and the spring security plugin. I would like to log in a predefined guest user at application start up but not sure how to achieve this.
How do I programmatically log in a user? (I'm attempting this in bootstrap but can not find what to import for the AuthToken class)
Where is this best done - i.e. in the bootstrap config?
Okay I found a solution... it's a bit raw, and I'm not sure this is the best place for it at application startup, but it achieves what I wanted.
So in Bootstrap file I have implemented the following:
Here's my imports:-
import grails.plugin.springsecurity.rest.token.AccessToken
import grails.plugin.springsecurity.rest.token.generation.TokenGenerator
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.BadCredentialsException
import org.springframework.security.core.Authentication
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.userdetails.UserDetails
...after all bootstrapping of my user I want to auto log in a Guest user and then generate the JWT refresh and access token too...
/* Login in guest user on application startup */
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("guest", "guest");
token.setDetails(tttGuest);
try {
//doing actual authentication
Authentication auth = authenticationManager.authenticate(token);
log.debug("Login succeeded!");
//setting principal in context
SecurityContextHolder.getContext().setAuthentication(auth);
//Generate JWT access token and refresh token
AccessToken accessToken = tokenGenerator.generateAccessToken(springSecurityService.principal as UserDetails)
return true
} catch (BadCredentialsException e) {
log.debug("Login failed")
return false
}
The only part left to do is to figure out how to communicated the tokens back to the client application.
New at Spring Security here. I was looking at this link 'https://docs.spring.io/spring-security/site/docs/current/guides/html5/form-javaconfig.html#grant-access-to-remaining-resources' and got really stumped at the section Configuring a login view controller`.
When I'm creating a typical form, I usually make the html page that, on click, calls a method in my custom #controller, which sends to my logic, etc.
However, in their example, they state that no controller is needed because everything is 'default'. Can someone explain exactly how their login form can 'connect' to their authentication object? It looks like somehow the credentials can magically pass into the Authentication object despite having no controller method.
Thanks!
There is no controller. When you use the formLogin() method, a UsernamePasswordAuthenticationFilter is registred in the security filter chain and does the authentication job. You can look at the source code here:
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
String username = obtainUsername(request);
String password = obtainPassword(request);
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
username = username.trim();
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
username, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
Take again a look into https://docs.spring.io/spring-security/site/docs/current/guides/html5/form-javaconfig.html#configuring-a-login-view-controller. In the code snippet you can actually see, that an internal controller with the request mapping /login is registered. That is why you do not have to implement it on your own. All authentication transfer between view, internal controller and the authentication manager in the background is handled completely transparent to you.
I am creating an application using Spring with Oauth2 as a backend for two apps (provider app and a consumer app). I have two different types of users; Providers, and consumers, each with its own db table.
The problem I am facing is that I cannot find a way to know if the request is coming from a provider or a customer, as each one will be in a different db table.
The username is Not unique between the two tables. So, a provider and a consumer can have the same username (and password).
I think any of the following solutions will suffice, however, I can’t find any way to implement any of them.
Having two different endpoints for each user class. e.g. “/provider/oauth/token” and “/consumer/oauth/token”. Each with its custom authentication manager.
Or: Having two authorization servers in the same Spring application, and then mapping their “/oauth/token” to different endpoints.
Or: Sending custom data in the oauth request to know where the request is coming from, and then dynamically selecting an authentication manager.
Or: Associating different authentication manager to different OAuth clients, and then ensuring that each app will have its respective client ID.
If any of these solutions is possible, or if there is another way to accomplish this, please let me know.
Any help is appreciated.
Edit - Solution
Following the answer below, I added another client with a different client ID, check the id in the UserDetailsService and then decide which db to use. Here is the code:
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
User user = (User) authentication.getPrincipal();
String username = user.getUsername();
if (username.equals(OAuth2Configuration.provider_app))
// Load from provider db
else if (username.equals(OAuth2Configuration.consumer_app))
// Load from consumer db
else
throw new UsernameNotFoundException("ClientID " + username + " not found.");
}
};
}
UsernamePasswordAuthenticationToken is used as /oauth/token is protected with Basic Oauth using the client id and secret.
I think you should be able to look inside SecurityContextHolder.getContext().getAuthentication.
This should be an instance of OAuth2Authentication, from which you can (after you cast) call getOAuth2Request() to get the original Oauth2Request details.
With this information you can have a single UserDetailsService that can delegate lookups to the correct db tables. You could use scopes or resourceIds to help determine what db table to use.
You could use the third option. but this is not a good principal to follow. you can send a custom param in the oauth/token end point. it can be accessed by AutoWiring HttpServletRequest in the userDetailsService.
UserDetailsService
#Autowired
private HttpServletRequest httpServletRequest;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
try {
String userType = httpServletRequest.getParameter("user_type");
LOGGER.info("Load user method \n Username : " + username + "\nuser_type : " + userType);
if (userType == null) {
throw new CustomOauthException("User type is required !");
}
if (userType.equals(String.valueOf(MOBILE_USER))) {
//get user..
} else if (userType.equals(String.valueOf(DRIVER))) {
//get driver..
} else if (userType.equals(String.valueOf(ADMIN))) {
//get admin
}
throw new CustomOauthException("User type is not valid !");
} catch (Exception e) {
e.printStackTrace();
LOGGER.error("Exception : " + e.getMessage());
throw new CustomOauthException(e.getMessage());
}
}
I am developing an application in J2E with struts 2 and tomcat v6.
I have a login page in my application where the user will have to type his password by clicking on a virtual keyboard (made on my own).
Before the keyboard appears, i have an action to randomise the characters' . This action also encode all characters for security reasons and set the map of characters and code in session.
The authentication is done with a JDBC realm in tomcat.
What i am trying to do is to decode the user's password. I have tried a filter with the url-pattern "j_security_check" but i found it was not possible to catch this event in filter.
So I am trying to decode the password in the JDBC realm, but it is not working. I have tried to use ServletActionContext.getRequest() in the realm but I am facing a null pointer exception.
Is it possible to get the map stored in session in the realm ?
If it is not, any clues of how to do this are welcome because I haven't found any solution.
One posible solution is writing Custom Authenticator, extending FormAuthenticator
Eg.
//Will expand the basic FORM authentication to include auth based on request headers
public class CustomAuthenticator extends FormAuthenticator{
public boolean authenticate(Request request, Response response, LoginConfig config) throws IOException{
if(request.getUserPrincipal() == null){
Realm realm = context.getRealm();
//Pick the user name and password from the request headers
//you can decode the password here
if(username == null || pass ==null) return super.authenticate(....);
boolean authenticated = realm.authenticate(username, pass);
if(authenticated == false) return false;
//Set the username/password on the session and set the principal in request
session.setNote(Constants.SESS_USERNAME_NOTE, username);
session.setNote(Constants.SESS_PASSWORD_NOTE, password);
request.setUserPrincipal(principal);
register(request, response, principal, Constants.FORM_METHOD, username, pass);
}
return true;
}
}
See also: http://apachecon.com/eu2007/materials/UnderstandingTomcatSecurity.pdf and http://javaevangelist.blogspot.com/2012/12/tomcat-7-custom-valve.html
I've got a little webapp secured by spring-security using a username/password combo on a sql-db as credentials.
I now want to add facebook/twitter authentication with spring-social. Using the examples I am able to store the users credentials in my db. I'm now working on authenticating the user against his current session on my app using the following piece of code:
public String signIn(String userId, Connection<?> connection, NativeWebRequest request) {
User user = userService.getUserById(Long.parseLong(userId));
user.setPassword(this.passwordEncoder.encodePassword(user.getAccessToken(), this.salt));
this.userService.store(user);
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getDisplayName(), user.getAccessToken());
HttpServletRequest req = request.getNativeRequest(HttpServletRequest.class); // generate session if one doesn't exist
token.setDetails(new WebAuthenticationDetails(req));
Authentication authenticatedUser = this.authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authenticatedUser);
return "/user/dashboard";
}
The authentication works, I am not getting any BadCredential-exceptions. But after being redirected to /user/dashboard I am thrown back to the login.
I am out of ideas, a similar piece of code for authenticating the session is working after a classical signup.
Does anyone have any ideas why this happens or how to debug this?
Thanks very much in advance!
Hendrik
I have similar code that works for me, and also adds "remember me" support:
// lookup by id, which in my case is the login
User user = userService.findByLogin(userId);
// code to populate the user's roles
List<GrantedAuthority> authorities = ...;
// create new instance of my UserDetails implementation
UserDetailsImpl springSecurityUser = new UserDetailsImpl(user, authorities);
// create new Authentication using UserDetails instance, password, and roles
Authentication authentication = new UsernamePasswordAuthenticationToken(springSecurityUser, user.getPassword(), authorities);
// set the Authentication in the SecurityContext
SecurityContextHolder.getContext().setAuthentication(authentication);
// optional: remember-me support (must #Autowire in TokenBasedRememberMeServices)
tokenBasedRememberMeServices.onLoginSuccess(
(HttpServletRequest) request.getNativeRequest(),
(HttpServletResponse) request.getNativeResponse(),
authentication);