The Key Component in Spring Security

  •  The Authentication filter is a servlet filter class that will see if the user has authenticated
  • if not , it will send that requiest to authentication manager to check if the detail send by the user are correct 
  • if the username and password are valid, the authentication manager in turn uses authentication provider this is where the login logic or the authenication logic is defined.
  • the authentication provider will not fetch the user details from the database or from LDAP or in memory, it will user user detail service for that purpose.
  • it will use also password encoder becauase we dont want to store password in plain text so the password will be decoded the incoming password from the user will be encoded and then the comparision is done.
  • once the authentication provider check if  the authentication details the user name and password etc are correct than it will send the apporopriate response back to the authentication manager
  • authentication mangeer hands it back to the authentication filter if the user details are OK
  • the authentication filter will user a authentication success handler and store that authentication
  •  information the user entity it self in a security context, in an instance of security context, if the authentication failed it will use the authenication failure handler to send the appropriate response back to the client


Spring boot allow us to create and deploy our application rapidly
By simply adding the spring security by adding the given below spring boot starter dependency
than we will get all these component will be enabled 
and by default it will use Basic Authentication without you writing a line of code ,
the basic HTTP authentication will be enabled for your application
if you want to customize these defaults, you will create a java based spring configuration

Markt that class with @Configuration annotation and this class should extend 
WebSecurityConfigurerAdapter from spring once you do this you can override the default by overriding the configure method that are there in the class
you can change it from basic authentication to form based authentication or you can implement your own authentication logic as well

It also gives us various implementations of these interfaces we have seen for the User Detail Service
there is a in Memory User detail manager that we can use. we can use a Ldap manger if we organization is connecting to Ldap or we can use our own custom user detail service. which we will use to fetch that user data from the database.
And also we can create our own implementation of the authentication provider. instead of using the inbuild authentication provider , we will create our own authentication provider by implementing the AuthenticationProvider interface within which there is only one method called authenticate which will get the authentication details at runtime

Spring Security in Action:



HelloController.Java

@RestController

public class HelloController {

        @GetMapping("/hello")

public String hello() {

return "Spring Security Rocks!!";

}


}


Now check into Postman

Getting Status as 401Unauthorized


which means not authenticated also by browser getting given below screen


So this given above screen we are getting just because we have added Spring
Security Dependency in our code

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-security</artifactId>

</dependency>

So Spring Security Authentication Filter comes in automatically at runtime and than
it delegates it to the Authentication manager this will delegate to the Authentication
provider
So By default basic authentication is enabled when we add spring security dependency
and that is the reason we are seeing a unauthorized 401 error is getting back

and there is Default implementation of UserDetailService and password Encoder that is
used by the authentication provider, the job of the UserDetailService



The default implementation is to create a user called user and it generate the
password which you can see into your console as well
the given above generated password is UUID universal unique identifier
and This password store inMemory if you restart the application this will be gone
and new password will be generated and user as user

Now you will get the Response back
this kind of security we will not be use in the production

Even if you want to use basic authentication this is not how we will using it
we should not use default implementation of user detail, service and password encoder
we need to provide our own implementation of user Dtails service and password encoder
that will fetch the user from a Ldap or Database




We know now the Component that are involved with authentication is successful.
It will store the user information and that the login is successful inside the
security context
It will Generate a cookie called J Session id
This is typical process in java web application or JavaEE web Application.
It will send the cookie back
if we go to the header section of postman, go to the cookie on the right side
If you click on Cockie you can see JSessionId
This JSessionId only will store into Security context
So whenever we are hitting the api they will send that Cookie brack every time when we Hit
The Api, So along with the request, the cookie is also going the filter will use that cookie
See if is a corresponding log in response or authentication response in the security context
if security context is there it will not prompt for the login
That is the resond from second time onwards it doesnt ask for basic authentication.



Spring boot Security Before and After 3.0:
Before: we have to create a configuration class that extends the 
WebSecurityConfigurerAdapter class from spring security, and than we have to implement configuration method which is coming from 
WebSecurityConfigurerAdapter class whitin which we use HTTP Security and authentication manager builder etc. to configurate the security for our application
After: But starting spring boot 3.0 and higher, we no longer need to implement this interface or extend this, we simply create a class, mark it with configuration annotation and we expose out a bean called SecurityFilterChanin

This is new way to configure Security in spring boot

@Configuration

public class MySecurityConfig {


//this will customize or to configure the security for our application as it sees a bean

//being expose out at runtime, it will use that bean to configure security instead of

//the default security, so now everything is relies on what we have to return back here.

//default security will be override with the security filter chain bean.

@SuppressWarnings("removal")

@Bean

SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

http.httpBasic();

http.authorizeHttpRequests().anyRequest().authenticated();

return http.build();

}

}


The Next Step is to configure a custom user detail service so that we need

not use the default user and its default generated UUID password

To do that we have to expose out another bean called the UserDetailsService, bean
UserDetailsService bean call that userDetailsService is the method name and withing
this method we will have to return the userdetailsservice, we are going to use
In-Memory user details manager that is available that is implementation of UserDetailsService


@Bean

UserDetailsService userDetailsService() {

InMemoryUserDetailsManager userDetailService = new InMemoryUserDetailsManager();

UserDetails user = User.withUsername("khan")

.password(passwordEncoder().encode("world")).authorities("read").build();

userDetailService.createUser(user);

return userDetailService;

}

@Bean

BCryptPasswordEncoder passwordEncoder() {

return new BCryptPasswordEncoder();

}

1. First Method with UserDetailsService will create the User with username

and password also encode the password

2. Second method is used to decrypt the password when the user comes in and

trying to get access of the application with given password



Now Lets use Custome Authentiction Logic inside Authentication provider


Than we dont need the User Detail Service and Password Encoder to do that

Create New Class:MyAuthenticationProvider
Also implement AuthenticationProvider

We have two Methods after implementing AuthenticationProvider interface
1. public Authentication authenticate(Authentication authentication):
by this authentication object we can get UserName and Password



@Override

public Authentication authenticate(Authentication authentication) throws AuthenticationException {

String userName = authentication.getName();

String password = authentication.getCredentials().toString();

if("khan".equals(userName) && "world".equals(password)) {

return new UsernamePasswordAuthenticationToken(userName, password, Arrays.asList());

} else {

throw new BadCredentialsException("Invalid Username Or Password");

}

}




By Given Above our custom Authentication Provider will send back our

Authentication token to the authentication manager and authentication manager will

send back to this authentication token to the authentication filter

since the authentication is successfull, it will store that username and passwod in

security context or if its fail it will throw bad credential exception which we have

added into our customer authentication provider class than will get 401 access issue


2. public boolean supports(Class<?> authentication) : this second method supports so

we need to tell that the username and password authentication, token type

this method needs to return to boolean value

@Override

public boolean supports(Class<?> authentication) {

return authentication

                .equals(UsernamePasswordAuthenticationToken.class);

}

So at runtime the authentication manager passes this type within this authentication

object to see if this provider supports this type of authentication and we are

comparing it with username and password authentication token type

if they both are same yes, this provider support the username and password authentication

token type, you can use that


Complete class will be look like


@Component

public class MyAuthenticationProvider implements AuthenticationProvider {


@Override

public Authentication authenticate(Authentication authentication) throws AuthenticationException {

String userName = authentication.getName();

String password = authentication.getCredentials().toString();

if("khan".equals(userName) && "world".equals(password)) {

return new UsernamePasswordAuthenticationToken(userName, password, Arrays.asList());

} else {

throw new BadCredentialsException("Invalid Username Or Password");

}

}


@Override

public boolean supports(Class<?> authentication) {

return authentication.equals(UsernamePasswordAuthenticationToken.class);

}


}






















Comments