I've been looking into using Spring Security for the authentication/authorization of my web application (this will be JDBC based).
However, a core component seems to be left out from my perspective. How do I register/create new users? Is there an out of the box API for that?
Do i need to write user registration and management from scratch?
Things i need to do include:
- Registering a new user
- Resetting passwords
- Emailing a user to activate their account
- Emailing a user to reset their account.
Thank you in advance.
I use Spring Security on my project. The framework does not have an API for user creation or registration as you asked. For Spring Security to be generic and usable across multiple frameworks, it can only take you so far before you have to write custom code. You can't really get a more specific answer about a framework or tool to use because at this point you will just use the frameworks you are already using anyway.
If you've set it up to use users and roles in your database, from your data access layer you would create a record in the user table or update a password (preferably stored as a hash) in that record. And as Aravind said, Spring does provide email support.
If you really want to see one way to do it: I'm using Spring MVC, JSP, and Hibernate. I use Spring's form tags in a JSP to bind a new user form to a Person object, and my controller method passes that Person object to my Dao to persist it.
The controller method signature looks like this...
#RequestMapping(value = "/newUser", method = RequestMethod.POST)
public ModelAndView createNewUser(final #Valid #ModelAttribute Person user,
final BindingResult result,
final SessionStatus status,
final #RequestParam(value = "unencodedPassword", required = true) String password) {
...
user.getRoles().add(new Role(user, Role.APPLICATION_ROLE.ROLE_USER));
userDao.createNewUser(user);
...
}
and my PersonDao would use Hibernate to persist the user like so
#Transactional
public void createNewUser(Person user)
{
Session session = sessionFactory.getCurrentSession();
session.save(user);
session.flush();
}
Have a look at my answer here.
"I have implemented a JAVA project for this use case. It is open
source, based on Spring-Security. A release version is on
Maven-Central, so you do not need to compile it, but instead you can
fetch it as maven-dependency to your project!"
<dependency>
<groupId>com.ohadr</groupId>
<artifactId>authentication-flows</artifactId>
<version>1.5.0-RELEASE</version>
</dependency>
As far as I know, Spring Security does not have built in support for new user creation and registration. You will have to manage this yourself. However it does have emailing support. Check here for more on this.
Related
I'm building an OAuth2 authenticated app using Spring Boot, following this tutorial: https://spring.io/guides/tutorials/spring-boot-oauth2/
At one point, the endpoint /user sends back the currently logged in user.
The guide warns by saying:
"It’s not a great idea to return a whole OAuth2User in an endpoint since it might contain information you would rather not reveal to a browser client."
But it doesn't give any more information - what type of information should I not be revealing to a browser client?
Thanks!
In Spring Security 5.x, the OAuth2User is a specific OAuth2AuthenticatedPrincipal (very similar to a UserDetails but without any notion of a password). Even without a password, exposing it can (and often will) leak sensitive information, implementation details of your authentication scheme, etc. You can expose it if you choose, but the warning in the guide is suggesting that care should be taken so as not to expose anything considered sensitive, and you should consider alternatives before exposing it directly.
For example, you might consider creating a CustomUser class that is populated from claims on the OAuth2User using a custom OAuth2UserService (various examples in the advanced configuration section of the docs). You can also take various steps to decouple the representation of an oauth2 user in Spring Security from the representation of a user in your application (e.g. by using #AuthenticationPrincipal to resolve your own custom user or access claims). If the application itself does not need a custom user, you can simply map claims of the OAuth2User to a response in your custom endpoint, as demonstrated in the guide.
Finally, you can combine all of these techniques to make your /user endpoint a "one liner" again, as in:
#Target({ElementType.PARAMETER, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#AuthenticationPrincipal(expression = "customUser")
public #interface CurrentUser {}
#GetMapping("/user")
public CustomUser user(#CurrentUser CustomUser customUser) {
return customUser;
}
I'm not a big fan of Spring Security, I think it's too overrated. So i'm trying to use alternatives to secure my rest API, and one of them which I like is Spring sandwich which based on interceptors.
The only issue i have though is that I want smth similar to SecurityContextHolder.getContext().getAuthentication().getPrincipal();
so I don't have to pass the user every time but more of a global object.
Anybody has any idea how to do that?
ps: i'm using spring boot
Although I highly suggest reconsidering Spring Security, you can also use HttpSession as an alternative.
When an user logs in, you can store your 'User' object in his session like so:
#RequestMapping("/login")
public String login(HttpSession session, #RequestParam String username, #RequestParam String password) {
// check if user has right credentials ...
session.setAttribute("USER", user);
return "You have logged in successfully"; // you can also redirect instead, do as you wish
}
and then you can access the User object like so:
User user = (User)session.getAttribute("user");
you can also get the session from HttpServletRequest (request.getSession())
Alternatively, if you can't pass the object HttpSession to your controller for some reason, you can also autowire the session like so:
#Autowired
private HttpSession session;
See Spring Session for more details
I want to implement the login/logout (authentication/authorization) system of my Spring 4 MVC application with Spring Security.
Currently I use a very simple hand-made implementation which basically does nothing more than comparing the entered username and MD5 hashed password with the database values by looking up the user by the username using a custom service method and comparing the encrypted passwords.
If the passwords match, the username of the logged in member is saved in the session and a ControllerAdvice looks up the Member object for the user using the username in the session prior to each request. The checkLogin method returns true is username and password match:
#Service("loginService")
#Transactional
public class LoginServiceImpl implements LoginService {
private MemberDao dao;
//more methods
#Override
public boolean checkLogin(String username, String password) {
String hashedPassword = getPasswordHash(password);
return dao.checkLogin(username, hashedPassword);
}
}
This does work but is not a very elegant solution, does not handle different roles and is probably not very secure. Besides I want to become familiar with Spring Security.
Reading the official tutorial for Spring Security (http://docs.spring.io/spring-security/site/docs/4.0.4.RELEASE/reference/htmlsingle/#tech-userdetailsservice) the way to go to authenticate against the Login service method does not become clear to me.
The tutorial discusses authentication direct against the database but I cannot find anything about using a Service method to perform the authentication and in my layered architecture, the database is hidden behind the Servoce and Dao (Hibernate) layers.
Also most examples in the tutorial use XML based instead of Java based configuration which I use for my application.
After having search a lot with search engines, I still have not found a tutorial which implements Spring Security in a Spring MVC application using a familiar layered structure using a Service and Dao layer.
Do I need to bypass Service and DAO/Hibernate layers and authenticate directory against the database? Or write a custom authentication-provider implementing UserDetailsService as described in this post?
Spring Security 3 database authentication with Hibernate
And is configuring Spring Security possible with Java based configuration only? I am a bit lost with this issue so I hope for some hints...
Im using Spring 3.1.1 with Spring Security 3.2.0 with LDAP authencitation.
I have gotten it to a point that works fine and I can log in using my LDAP username and password, I can even display the username with this
<security:authentication property="principal.username" />, is currently logged in.
I want to know how, if at all possible, can I get the first name, surname, email address or other information like that stored in my LDAP credentials.
I've tried property="credentials" but this returns null...
PLEASE HELP!!
This is eerily similar to my question a few days ago:
How do I use a custom authorities populator with Spring Security and the ActiveDirectoryLdapAuthenticationProvider?
If you're not using Active Directory, you can simply extend the LdapAuthenticationProvider class and override the loadUserAuthorities method, in which you can capture the relevant user information based on the LDAP attributes for the user:
String firstName = userData.getStringAttribute("givenName");
String lastName = userData.getStringAttribute("sn");
//etc.
You can store these wherever or however you like, and you're only limited to the attributes available via LDAP. Then, you'd have to specify your LdapAuthoritiesProvider in the appropriate bean (ldapAuthoritiesPopulator, if memory serves).
I believe the above will work for non-AD LDAP, but you'll obviously need to test it to be sure. I recommend the LDAP browser for Eclipse provided by Apache Studios, if you're not already using it.
Implement your own UserDetailsContextMapper and load LDAP user properties into the UserDetails object
http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/#ldap-custom-user-details
I'm trying to convert a Stripes web app to Grails. The Stripes app uses Spring Security, but I would like the Grails app to use the Spring Security Grails plugin.
The app already has User and Role (Java) classes that I need to reuse, i.e. I cannot use the Grails domain classes that the s2-quickstart script generates.
The Spring Security plugin docs describe how to use an existing User domain class. The steps seem to be:
define a UserDetails implementation that reads from the existing User domain class
define a custom UserDetailsService implementation that returns instances of (1)
register an instance of (2) as a Spring bean named userDetailsService.
However the docs don't provide any information about how to use an existing Role class and the class that represents the many-to-many relationship between User and Role.
What other steps are necessary to use existing Role, User, and UserRole classes with the Grails Spring Security plugin? Is there any reason for me to run the s2-quickstart script if I don't want to generate any domain classes?
Follow-Up Questions to Burt's Answer
In the end, what you need is a new GrailsUser
Presumably GrailsUser here refers to the custom UserDetails implementation? In my case I'll probably just implement the interface directly. Does something like this seem reasonable?
class UserAdapter implements UserDetails {
private String password
private Collection<GrantedAuthority> springRoles
UserAdapter(User user) {
this.password = user.password
Collection<Role> roles = // load legacy Role objects
this.springRoles = roles.collect { new GrantedAuthorityImpl(it.authority) }
}
// If using password hashing, presumably this is the hashed password?
String getPassword() {
password
}
///////// other UserDetails methods omitted
Collection<GrantedAuthority> getAuthorities() {
springRoles
}
}
I'm not storing the whole User object within UserAdapter because of your warning about storing a potentially large object in the HTTP session.
what you need is.....and a List of GrantedAuthority instances (and the id if it's a GrailsUser)
If I use my own UserDetails implementation as above, then presumably I can ignore this comment about providing an id?
Finally, if I follow the approach outlined above, should I set these properties in Config.groovy and do I need to run the s2-quickstart script (or any others)?
Keep in mind that Spring Security doesn't care where the data comes from, it just needs a UserDetails instance when authenticating with the DAO auth provider and it can come from anywhere. It's convenient to use domain classes and database tables, but it's just one approach. Do what works for your data. In the end, what you need is a new GrailsUser (or some other impl) instance with the username and password set, the 3 booleans set, and a List of GrantedAuthority instances (and the id if it's a GrailsUser).
The simplest thing to do when you have legacy user and role data is to create a custom UserDetailsService. Use GORM, raw SQL queries, whatever you need to get the required data.
Another option is to write your own AuthenticationProvider like Glen did here: http://blogs.bytecode.com.au/glen/2010/01/15/hacking-custom-authentication-providers-with-grails-spring-security.html - although that's a larger solution that also involves a custom filter which you wouldn't need. The DAO provider uses a UserDetailsService but it's fine to create your own that combines the functionality into one class.
It's not a good idea to reuse your User domain class as the UserDetails though. Even if you implement the interface, you'd be storing a disconnected potentially large (if there are attached collections) object in the HTTP session. The POJO/POGO implementations (Spring Security's User class, the plugin's GrailsUser class, etc.) are very small and just a few Strings and booleans.
within the config.groovy file you have to specify your domain classes to use:
grails.plugins.springsecurity.userLookup.userDomainClassName = 'your.package.User'
grails.plugins.springsecurity.userLookup.authorityJoinClassName = 'your.package.UserRole'
grails.plugins.springsecurity.authority.className = 'your.package.Role'
i thinks it's not neccessary to implement your own userDetail service, because spring security uses
SpringSecurityUtils.securityConfig.userLookup
method to determine the domain class you configured before. your domain classes must provide the required fields and relations.