Spring security grails plugin - spring

I'm using Spring security grails plugin v2.0.0 RC5 in my grails application , but i noticed something , that while login to the application the username is not case sensitive for instance if you wrote user or USER both will login successfully. What i need to do is to make the username case sensitive.
i found the that isLoggedIn action in springSecurityService handling the login but i can't see anything in it any checking of the provided username or password.
here is the isLoggedIn code :
boolean isLoggedIn() {
def authentication = SCH.context.authentication
authentication && !authenticationTrustResolver.isAnonymous(authentication)
}
Am i searching the the right place ?

There is a configuration property for that. https://grails-plugins.github.io/grails-spring-security-core/3.2.x/index.html#domainClassProperties
userLookup.usernameIgnoreCase

In my Grails app I'm using the Spring Security plugin and have defined a custom userDetailsService Spring bean in order to control how user and role data is retrieved, e.g.
class MyUserDetailsService implements GrailsUserDetailsService {
/**
* Some Spring Security classes (e.g. RoleHierarchyVoter) expect at least one role, so
* we give a user with no granted roles this one which gets past that restriction but
* doesn't grant anything.
*/
static final List NO_ROLES = [new GrantedAuthorityImpl(SpringSecurityUtils.NO_ROLE)]
UserDetails loadUserByUsername(String username, boolean loadRoles) {
return loadUserByUsername(username)
}
UserDetails loadUserByUsername(String username) {
User.withTransaction { status ->
User user = User.findByUsername(username)
if (!user && user.username.equal(username)) {
throw new UsernameNotFoundException('User not found', username)
}
def authorities = user.authorities.collect {new GrantedAuthorityImpl(it.authority)}
return new CustomUserDetails(
user.username,
user.password,
user.enabled,
!user.accountExpired,
!user.passwordExpired,
!user.accountLocked,
authorities ?: NO_ROLES,
user.id,
user.name)
}
}
}
Now you will see
**if (!user && user.username.equal(username)) {**
this will solve your problem.
But here is another problem, your implementation also depends on your database because like MySQL is case insensitive, so if you search a user with name Joy then it will return all the user doesn't wich have name joy doesn't matter it is in capital letter or small letter.
So you need check in database value before persisting new user.
also, another problem is, if you will check the user domain
username blank: false, unique: true, email: true
username is unique, means you can't insert username joy again if Joy exists in db, so you need to change it and write your own custom logic to handle this problem.

Related

Roles and Permission at method level Spring boot

I need to have authorization at the method level so that the users with proper permissions only can access it. The method will contain a token as a parameter. I need to make an API call passing the token and get the user email id. Once I have the email id, I need to fetch the user's roles & permissions from the database. Then I invoke the method if the user have appropriate roles else return a 403 error.
Is there a way to get this done in spring boot? I will have multiple methods behind authorization and would like to have some kind of annotation at method level.
Thanks.
#PreAuthorize annotation is what you want
Please read the following link for spring method level authorization
baeldung method authorization
you will also need to undestand SPEL(Spring Expression Language) as this is what the PreAuthorize method gets as parameter , link can be found here
please note that spring uses the SecurityContext to get the user data(Role etc..), meaning that the user already passed the login(authentication) stage and has SecurityContext loaded for said user
Example:
//other annotations
#PreAuthorize("hasRole('ROLE_VIEWER')") // hasRole('ROLE_VIEWER') -> this is SPEL
public ResponseEntity<String> methodName() {
//method
}
You can use #PreAuthorize with more flex as:-
#PreAuthorize("#securityService.hasPermission({'PERMISSION_1'})")
and service:-
#Component("securityService")
public class SecurityService {
public boolean hasPermission(PermissionEnum... permissions) {
Collection<? extends GrantedAuthority> authorities = SecurityContextHolder.getContext().getAuthentication()
.getAuthorities();
for (PermissionEnum permission : permissions) {
if (authorities.contains(new SimpleGrantedAuthority(permission.toString))) {
return true;
}
}
return false;
}
}
You can make it as you want.
For more
https://dreamix.eu/blog/java/implementing-custom-authorization-function-for-springs-pre-and-post-annotations
https://try2explore.com/questions/10125443

Spring Social, Create connection for existing local users on signin

I am trying to allow existing local users to signin using Spring Social, primarily google, and automatically create a new userconnection if email matches local account.
I have only found examples for implicit signup (requires/creates a new account), new user signup (default action if SpringSocial fails to find a UserConnection) and the connect option while the current user is logged in.
How can I extend SpringSocial to let me check for existing social user / local user email match, create a user connection to existing local user and then sign them into both local and social?
You can use the implicit sign up to find an account instead of creating a new one.
Modifying the code found for implicit sign up, you can do something similar to the following:
public class AccountConnectionSignUp implements ConnectionSignUp {
private final AccountRepository accountRepository;
public AccountConnectionSignUp(AccountRepository accountRepository) {
this.accountRepository = accountRepository;
}
public String execute(Connection<?> connection) {
UserProfile profile = connection.fetchUserProfile();
Account account = accountRepository.findAccountByEmail(profile.getEmail());
return account == null ? null : account.getUsername();
}
}
You will need to implement Account and AccountRepository to support an email property, then use the repository to find account by email. If the repository cannot find an account, return null.

Grails 2.2.3 + Spring security core + Multi-tenant Single DB plugin

I am new to grails and I am trying to implement spring security core and Multi-tenant single db plugin.
I have implemented the spring security core first and implemented custom AuthenticationProvider and Authentication.
Then I have installed the multi-tenant single db plugin and ran the 'mt-spring-security' script that automatically created custom tenantResolver and tenantRepository. I have hard-coded the tenantId in tenantResolver for testing purpose.
I have added the #MultiTenant annotation in the domain classes.
#MultiTenant
class ClientUser implements Serializable {
long idclient_user
Userprofile user
Client client
int tenantId
...
}
In the AuthenticationProvider, the ClientUser data is not filtered for the current tenant. It is bringing the data the all the tenant.
class ClientAuthenticationProvider implements AuthenticationProvider {
Authentication authenticate(Authentication auth) throws AuthenticationException {
ClientAuthentication authentication = auth
String password = authentication.credentials
String username = authentication.name
String clientName = authentication.clientName
...
Userprofile.withTransaction { status ->
def user = Userprofile.findWhere(username: username)
def client = Client.findWhere(clientname: clientName)
def clientUser = ClientUser.findWhere(client: client, user: user) <-- NOT FILTERED FOR THE CURRENT TENANT. I HARD-CODED INVALID TENANTID IN THE TENANTRESOLVER AND EXPECTING IT TO FAIL BUT IT STILL FINDS THE USER.
if (!clientUser) {
throw new UsernameNotFoundException('User not found', username)
}
...
}
...
result
}
I am not sure how the multi-tenant and spring security works together. I am having a hard time understanding the Architecture/design.
If anyone could provided me with a sample implementation or point me in the right direction, it will be really helpful.
Thanks,
dinesh
The problem was that the multitenant filter was registered before the spring security filter so the tenantResolver was not called until after the Spring security authentication. I fixed this problem by setting the resolveTenantBeforeLogin to true in the config.groovy
In config.groovy, add this line
multiTenant.resolveTenantBeforeLogin=true
After i added this line, the tenantResolver is called first and then the authentication.

How do roles and rights translate to Spring Security?

In my applications I usually create three tables for access management. Roles, Rights and an association table that maps between Roles and Rights.
I am trying to translate this approach to Spring security and after reading [this article][1] I thought I was on the right track. I created a custom AuthenticationProvider and implemented the authenticate() method like so:
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UserProfile profile = userProfileService.findByEmail(authentication.getPrincipal().toString());
if(profile == null){
throw new UsernameNotFoundException(String.format("Invalid credentials", authentication.getPrincipal()));
}
String suppliedPasswordHash = DigestUtils.shaHex(authentication.getCredentials().toString());
if(!profile.getPasswordHash().equals(suppliedPasswordHash)){
throw new BadCredentialsException("Invalid credentials");
}
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(profile, null, profile.getAuthorities());
return token;
}
The profile.getAuthorities() method creates a list of Rights (rights are wrapped in my own implementation of GrantedAuthority). So, the UsernamePasswordAuthenticationToken object is created with this list. This is the UserProfile.getGrantedAuthorities() method that takes care of this:
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<ProduxAuthority> authorities = new HashSet<ProduxAuthority>();
for (Role role : roles) {
for (Right right : role.getRights()) {
ProduxAuthority produxAuthority = new ProduxAuthority(right.getName());
authorities.add(produxAuthority);
}
}
return authorities;
}
My question is whether this is a correct approach. I am getting the impression that I should stuff roles into GrantedAuthorities instead of rights, but I would like to use rights to secure methods and urls, because it gives me more fine grained control over authorization. How would I accomplish this? And what is the difference between a ROLE and a PERMISSION in Spring? Do permissions map to rights and could I use hasPermission() to secure stuff bases on rights instead of roles?
I am going to answer my own question again:
Spring doesn't know rights and permissions that are used by the hasPermission method apply only to the relatively complex Domain Object Security/ACL in Spring security. Spring's simple security knows just roles and roles or more generic "permissions" (in the general sense of the word, not to be confused with permissions in Domain Object Security/ACL) like IS_AUTHENTICATED_ANONYMOUSLY are handed to Spring in the third constructor parameter of the Authentication object's.
I summerized everything on my own website and created an example implementation that stuffs rights into roles and in that way still manages to be pretty flexible.
http://en.tekstenuitleg.net/blog/spring-security-with-roles-and-rights

Spring Security 2.0 Facebook Connect

I´m trying to implement Facebook login to our Spring Framework 2.5 based application which has usual login/password authentication already.
I got to this part of code in my controller where i have user´s Facebook data in userFb object:
String code = request.getParameter("code");
String accessToken = fbStuffKeeper.retrieveAccessToken(code);
facebookClient = new DefaultFacebookClient(accessToken);
User userFb = facebookClient.fetchObject("me", User.class);
I can check if user is already in DB and if not I am able to store him in a DB and store his FB_uid and other necessary credentials.
Problem is that I want to login this user after some condition if he is already authorized to system.
My current authentication manager decides by this rule:
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="select username, password, confirmed, 1 AS enabled FROM person WHERE confirmed=1 and username=?"
authorities-by-username-query="select username, authority from person where username=?"/>
<password-encoder hash="md5"/>
</authentication-provider>
So my question is: How do I login user found in DB who tries to connect using Facebook? Another authentication provider? Is there any way to do his login using some similar code as is mine mentioned one?
Thank you very much.
***EDIT:
Thank you very much. It looks it might help. I have now one user in DB which I want to login. I made this code in the controller:
User userFb = facebookClient.fetchObject("me", User.class);
Person person = personDao.getPersonByFbUid(userFb.getId());
GrantedAuthority[] grantedAuthorities = new GrantedAuthorityImpl[1];
grantedAuthorities[0] = new GrantedAuthorityImpl(person.getAuthority());
Authentication a = new FacebookAuthenticationToken(grantedAuthorities, person);
a.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(a);
I also created FacebookAuthenticationToken:
public class FacebookAuthenticationToken extends AbstractAuthenticationToken {
private Person person;
public FacebookAuthenticationToken(GrantedAuthority[] authorities, Person person) {
super(authorities);
this.person = person;
}
public Object getCredentials() {
return person;
}
public Object getPrincipal() {
this.person;
} /* + Person getter and setter */
And all works fine now. Thank you once more for your help.
One possible way is following. Although it may not be perfect, but it works well.
Create a FacebookAuthenticationToken class, that extends AbstractAuthenticationToken and holds your facebook user object (assuming it to be FacebookUser).
After your code you mentioned above, append the following code right after it into the same controller:
String code = request.getParameter("code");
String accessToken = fbStuffKeeper.retrieveAccessToken(code);
facebookClient = new DefaultFacebookClient(accessToken);
User userFb = facebookClient.fetchObject("me", User.class);
// Find FacebookUser with current FB_uid, create new if found none, load its information in an instance of FacebookUser
Authentication a = new FacebookAuthenticationToken(fbUserObject);
a.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(a);
// your authentication is complete, redirect to some other page

Resources