Spring Security: Password Configurations

Security
Security

In this article we will be discussing on how to configure a password with Spring Security and detail about Authentication architecture in Spring

 Spring security is securing a web application API developed in spring framework .It is comprised of Authentication and Authorization.

Authentication is all about who should get the access to the API and who should not. Whereas Authorization is which API one can get access to?

Authentication in Spring can be done in 2 ways in terms of user password configurations.

  • Using database to store the password .
  • Using Active directory like LDAP to store the password .

When the user information is stored in a db , spring provides 2 ways to authenticate.

  • UserDetailService
  • JDBCAuthentication

When the user information is stored in some active directory like ldap , we can use spring ldap authentication .

Image title

 

Authentication Manager / Authentication Provider

Authentication manager is the interface that provides the authentication mechanism for any object. The most common implementation of it is the Provider which delegates to different AuthenticationProvider. AuthenticationProvider is similar to AuthenticationManager interface but has an extra method support() which checks the object supports the authentication type or not .

public interface AuthenticationProvider {

 Authentication authenticate(Authentication authentication)
throws AuthenticationException;

  boolean supports(Class<?> authentication);

}

Sometimes we have logical group of section in the application which needs to be authenticated differently. And each group is going to have a dedicated AuthenticationManager.

Spring security provides a way of configuring the AuthenticationManager with the help of a helper class AuthenticationManagerBuilder class which is used for setting up authentication using JDBC , LDAP or custom UserDetailsService .

Configure Security:

The below examples are present in https://github.com/jokumar/task-planner/tree/master/spring-security/task-planner

For simplicity purpose I have used h2 database and a single table to hold the user , role and password. In real scenario , role should be part of a different table .

USER table

user_id name password role
joy Joydip 123 ROLE_USER
admin Admin 8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918 ROLE_ADMIN

Password is sha256 encoded .

Create a data.sql for loading the insertion query on server startup to h2 database:

insert into user (user_id, name,password,role) values ('joy','Joydip','A665A45920422F9D417E4867EFDC4FB8A04A1F3FFF1FA07E998E86F7F7A27AE3','ROLE_USER')

insert into user (user_id, name,password,role) values ('admin','admin','8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918','ROLE_ADMIN')

Create a configuration class like below :

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Override
public void configure(AuthenticationManagerBuilder auth)
throws Exception {
// Various authentication to follow 
}


@Override
protected void configure(HttpSecurity http) throws Exception {
//various authorizations to follow 
}

}

Changes in pom.xml

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

@EnableWebSecurity is the marker annotation which tells spring to apply the configuration class to the global WebSecurity. Adding spring-boot-starter-security jar itself brings multiple spring security jars in the classpath which itself will enable the security to display the out of the box spring security login page.

 

  • JDBC Authentication

 

Update the configure method like below to enable jdbcauthentication :

@Override
publicvoid configure(AuthenticationManagerBuilder auth) throws Exception {

auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery("select user_id,password, 'true' as enabled from user where user_id=?")

.authoritiesByUsernameQuery("select user_id, role from user where user_id=?").passwordEncoder(new ShaPasswordEncoder(256));

}
  • Custom UserDetailsService

 

– Add the Spring data jpa library in pom.xml .

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

– Create a custom UserRepository

@Transactional
public interface UserRepository extends JpaRepository<User, String> {

}

– Create a SecureUser extending the User class and implementing UserDetails to handle the Roles and setting the userid and the password.

public class SecuredUser extends User implements UserDetails {

private static final long serialVersionUID = 1L;

public SecuredUser(User user){

this.setUserId(user.getUserId());
this.setName(user.getName());
this.setPassword(user.getPassword());
this.setRole(user.getRole());
}


@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new ArrayList<>();

//TODO Currently handled with one role for an user
String userRole = super.getRole();
if(userRole != null)
{
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(userRole);
authorities.add(authority);
}
return authorities;
}

@Override
public String getUsername() {
return super.getUserId();
}

@Override
public boolean isAccountNonExpired() {
return true;
}

@Override
public boolean isAccountNonLocked() {
return true;
}

@Override
public boolean isCredentialsNonExpired() {
return true;
}

@Override
public boolean isEnabled() {
return true;
}

}

– Create a UserDetailsServiceImpl an implementation of UserDetailsService

@Component
public class UserDetailServiceImpl implements UserDetailsService {

@Resource
UserRepository userrepository;

@Override
public UserDetails loadUserByUsername(String userId) throws UsernameNotFoundException {
User user=userrepository.findOne(userId);

return new SecuredUser(user) ;
}

}

– Update the configure class now :

@Override
public void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(userDetailServiceImpl).passwordEncoder(new ShaPasswordEncoder(256));
}
  • LDAP Authentication 

Authentication where credentials are stored in Active directory .We will use a sample active directory coming from spring . The server will be setup in 8389 port.

-Add the following in the pom.xml

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
</dependency>
<dependency>
<groupId>com.unboundid</groupId>
<artifactId>unboundid-ldapsdk</artifactId>
</dependency>

– Add the ldap configuration in application.properties

spring.ldap.embedded.ldif=classpath:test-server.ldif
spring.ldap.embedded.base-dn=dc=springframework,dc=org
spring.ldap.embedded.port=8389

– Created a test-server.ldif in resources folder like below :

dn: dc=springframework,dc=org
objectclass: top
objectclass: domain
objectclass: extensibleObject
dc: springframework

dn: ou=roles,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: roles

dn: ou=people,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: people

dn: uid=admin,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Admin1
sn: Admin1
uid: admin
userPassword: admin


dn: uid=joy,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: joydip
sn: Kumar
uid: joy
userPassword: 123


#ROLES
dn: cROLE_USERER,ou=roles,dc=springframework,dc=org
objectclass: top
objectclass: groupOfNames
cnROLE_USERER
member: uid=joy,ou=people,dc=springframework,dc=org

dn: cROLE_n=ADMIN,ou=roles,dc=springframework,dc=org
objectclass: top
objectclass: groupOfNames
cnROLE_ADMININ
member: uid=admin,ou=people,dc=springframework,dc=org

– Update the configure method :

@Override
public void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.ldapAuthentication()
.userDnPatterns("uid={0},ou=people")
.groupSearchBase("ou=roles")
.contextSource().url("ldap://localhost:8389/dc=springframework,dc=org").and()
.passwordCompare().passwordAttribute("userPassword");
}

This is how it behaves in application for all three spring authentication of the same user and credentials:

Image title

Image title

Thank You and Happy Coding !!

Digiprove sealCopyright secured by Digiprove © 2019 Geeks 18

1 Comment

Leave a Reply

Your email address will not be published.


*