Spring boot security get username and password from authentication login to access rest services - spring

I am new to Spring. Client requests to access the rest services, giving username and password in http login provided by Spring, as shown in the image. I don't want to save credentials('username and password') in the application.properties. When I provide the credentials and enter login button, I need to read data (in my case username-'root' and pwd-'root') provided by the user from login and use it in my algorithm, do the process and then authenticate. Is there a way?
Please help me, if anyone has any idea.
authentication login screen
Here is my sample code:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private MyBasicAuthenticationEntryPoint authEntryPoint;
#Autowired
private MyUserDetailsService userDetailsService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// auth.inMemoryAuthentication().withUser("user1").password("user1Pass").roles("ADMIN")
// .and().withUser("user2").password("user2Pass").roles("ADMIN");
auth.authenticationProvider(authenticationProvider());
}
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
// provider.setPasswordEncoder(new BCryptPasswordEncoder());
return provider;
}
// I am trying like this but not sure is this the right way
public void details(User user) {
String name = user.getName();
String password = user.getPassword();
System.out.println("name " + name + "password" + password);
}
// I am trying like this but not sure is this the right way
public void userDetails(UsernamePasswordAuthenticationFilter filter) {
String usernameParameter = filter.getUsernameParameter();
System.out.println(usernameParameter);
String passwordParameter = filter.getPasswordParameter();
System.out.println(passwordParameter);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests().anyRequest().authenticated();
http.httpBasic().authenticationEntryPoint(authEntryPoint);
}
}
#Component
public class MyBasicAuthenticationEntryPoint extends
BasicAuthenticationEntryPoint{
#Override
public void commence(HttpServletRequest request, HttpServletResponse
response,
AuthenticationException authException) throws IOException,
ServletException {
response.addHeader("WWW-Authenticate", "Basic realm=" +
getRealmName());
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
PrintWriter printWriter= response.getWriter();
printWriter.println("Http Status 401-" + authException.getMessage());
}
#Override
public void afterPropertiesSet() throws Exception {
//RealName appears in the login window
setRealmName("Rashmi");
super.afterPropertiesSet();
}
}
#SpringBootApplication
public class SpringRestfulWebServiceApplication extends
SpringBootServletInitializer {
#Autowired
CustomerDetailsController customerDetailsController;
public static void main(String[] args) {
SpringApplication.run(SpringRestfulWebServiceApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder
application) {
return application.sources(SpringRestfulWebServiceApplication.class);
}
}

Related

How do I implement conditional authentication in spring security based on user selection between LDAP and JDBC?

Hope you all are doing good and safe. I have an application which will allow a user to login either by using his LDAP credentials or using his credentials stored on database. I was able to configure separate jdbc and ldap authenticator but how can I implement it conditionally? Say, a user selects LDAP radio button on login page then it should trigger LDAP authentication and if user selects database authentication, then it should trigger jdbc authentication. Any help would be highly appreciated.
JDBC authenticator:-
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService userDetailsService;
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// TODO Auto-generated method stub
http.authorizeRequests()
.antMatchers("/admin").hasAnyRole("ADMIN")
.antMatchers("/user").hasAnyRole("ADMIN", "USER")
.antMatchers("/").permitAll()
.and().formLogin();
}
#Bean
public PasswordEncoder getPasswordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
**LDAP authenticator:-**
#EnableWebSecurity
public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter {
Logger logger = LoggerFactory.getLogger(this.getClass());
#Autowired
private UserDetailsService userDetailsService;
#Autowired
AuthenticationSuccessHandler authenticationSuccessHandler;
#Autowired
private AuthenticationFailureHandler authenticationFailureHandler;
#Bean
public AuthenticationFailureHandler authenticationFailureHandler() {
return new AuthenticationFailureHandler() {
String message = "";
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
if (exception.getClass().isAssignableFrom(UsernameNotFoundException.class)) {
message = "User Not Found";
} else if (exception.getClass().isAssignableFrom(DisabledException.class)) {
message = "Account Disabled";
} else if (exception.getClass().isAssignableFrom(BadCredentialsException.class)) {
message = "Bad Credentials";
}
else if (exception.getClass().isAssignableFrom(LockedException.class)) {
message = "Account Locked";
}
else {
message = "Internal Server Error";
}
response.sendRedirect("/WisoKeyinPortal/login?error=" + message);
}
};
}
#Bean
public UserDetailsService userDetailsService() {
return super.userDetailsService();
}
#Bean
public AuthenticationProvider authProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(new BCryptPasswordEncoder());
return authenticationProvider;
}
/*---------------------------For QA comment from here-------------------------------*/
#Bean public AuthenticationManager authenticationManager() { return new
ProviderManager(Arrays.asList(activeDirectoryLdapAuthenticationProvider()));
}
#Bean public AuthenticationProvider
activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new
ActiveDirectoryLdapAuthenticationProvider("xyz.com", "ldap://xyz.com");
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
provider.setSearchFilter("sAMAccountName={1}"); return provider; }
/*----------------------------For QA comment ends here-----------------------------*/
#Override
protected void configure(HttpSecurity http) throws Exception {
String[] staticResources = { "/css/**", "/images/**", "/fonts/**", "/scripts/**", };
http.csrf().disable().authorizeRequests().antMatchers("/login**").permitAll().antMatchers(staticResources)
.permitAll().anyRequest().authenticated().and().formLogin().loginPage("/login").permitAll()
.successHandler(authenticationSuccessHandler).failureHandler(authenticationFailureHandler).and()
.logout().invalidateHttpSession(true).clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/login").permitAll();
//.and().sessionManagement().invalidSessionUrl("/login?error=session");
}
#Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
//authManagerBuilder.inMemoryAuthentication().withUser("admin").password("pass").roles("ADMIN");
/*---------------------------For QA comment from here-------------------------------*/
authManagerBuilder.authenticationProvider(
activeDirectoryLdapAuthenticationProvider())
.userDetailsService(userDetailsService());
/*---------------------------For QA comment from here-------------------------------*/
}
}

Custom AuthenticationProvider not getting called

I am developing a spring boot 2 application.I am trying to implement spring security for that.I have used a custom AutenticationProvider for that.But it is not getting called .Spring authentication is working however. please help me to resolve this issue.I have tried many ways,but it wont worked.I am using jwt to create tokens .
WebSecurityConfigurerAdapter implementation class
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
#ComponentScan
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
#Autowired
private SecurmailSecurityProvider provider;
#Override
protected void configure(AuthenticationManagerBuilder authentication) throws Exception {
authentication.authenticationProvider( getKBServicesAuthenticationProvider());
}
#Bean
protected AuthenticationProvider getKBServicesAuthenticationProvider() {
return new SecurmailSecurityProvider();
}
#Bean
public JwtAuthenticationFilter authenticationTokenFilterBean() throws Exception {
return new JwtAuthenticationFilter();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().
authenticationProvider(provider).
authorizeRequests()
.antMatchers(MessageController.URL_AUTHENTICATE).permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http
.addFilterBefore(authenticationTokenFilterBean(), SecurityContextHolderAwareRequestFilter.class);
http.headers().frameOptions().disable();
}
Custom Authentication provider class
#Component
#Primary
public class SecurmailSecurityProvider implements AuthenticationProvider {
#Autowired
MessageClientRepository clientRepo;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (authentication.isAuthenticated()) return authentication;
SmAuthenticationToken token = (SmAuthenticationToken) authentication;
if (token.getGuid() != null && !token.getGuid().trim().isEmpty()) {
MessageClient client = clientRepo.findByGuid(token.getGuid());
if (client != null) {
return new SmAuthenticationToken(client);
}
}
return null;
}
#Override
public boolean supports(Class<?> authentication) {
return (SmAuthenticationToken.class.isAssignableFrom(authentication));
}
Already you autowired the CustomAuthentication provider by using
#Autowired
private SecurmailSecurityProvider provider;
again you are creating bean and passing that CustomAuthentication provider
#Bean
protected AuthenticationProvider getKBServicesAuthenticationProvider() {
return new SecurmailSecurityProvider();
}
Instead below code
#Autowired
private SecurmailSecurityProvider provider;
#Override
protected void configure(AuthenticationManagerBuilder authentication) throws Exception {
authentication.authenticationProvider( getKBServicesAuthenticationProvider());
}
#Bean
protected AuthenticationProvider getKBServicesAuthenticationProvider() {
return new SecurmailSecurityProvider();
}
Use this code
#Autowired
private SecurmailSecurityProvider provider;
#Override
protected void configure(AuthenticationManagerBuilder authentication) throws Exception {
authentication.authenticationProvider(provider);
}
And also Custom Authentication Provider implementation should be like this below:
#Component
public class SecurmailSecurityProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
if (shouldAuthenticateAgainstThirdPartySystem()) {
// use the credentials
// and authenticate against the third-party system
return new UsernamePasswordAuthenticationToken(
name, password, new ArrayList<>());
} else {
return null;
}
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}

Spring Boot Basic Auth for each request, username validated for later requests

I have enabled the http basic auth in spring boot. I am seeing strange results when calling from Postman
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private ApiUserDetailsService userDetails;
#Bean
public ShaPasswordEncoder passwordEncoder() {
return new ShaPasswordEncoder();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
ReflectionSaltSource salt = new ReflectionSaltSource();
salt.setUserPropertyToUse("username");
DaoAuthenticationProvider dao = new DaoAuthenticationProvider();
dao.setUserDetailsService(userDetails);
dao.setPasswordEncoder(passwordEncoder());
dao.setSaltSource(salt);
auth.authenticationProvider(dao);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated().and().csrf().disable().httpBasic();
}
Custome Userdetails
#Service
public class ApiUserDetailsService implements UserDetailsService {
#Autowired
private JdbcTemplate jdbcTemplate;
#Value("${spring.queries.users.query}")
private String usersQuery;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
List<UserDetails> usersBasedOnUserName = getUsersBasedOnUserName(username);
if (usersBasedOnUserName.size() == 0) {
throw new UsernameNotFoundException("Username " + username + " not found");
}
return usersBasedOnUserName.get(0);
}
private List<UserDetails> getUsersBasedOnUserName(String username) {
return jdbcTemplate.query(this.usersQuery, new String[] {username}, new RowMapper<UserDetails>() {
#Override
public UserDetails mapRow(ResultSet rs, int rowNum) throws SQLException {
String username = rs.getString(1);
String password = rs.getString(2);
return new User(username, password, AuthorityUtils.NO_AUTHORITIES);
}
});
}
}
For the fist time I execute the request, it expects the correct credentials. After I enter correct credentials, I get the result. But when I try for the the same request without credentials or diffrent password keepign username same, I wont get 401 error.
I will get 401 error only when I chnage username.
My API needs to be validated against each request.
Am I doing some thing wrong here.
Adding the stateless to config helped to solve issue.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests().anyRequest().authenticated().and().csrf().disable().httpBasic();
}

how to share User Principal/ securityContext on Public pages with permitAll() in spring security OAuth2

We have developed a SSO application in spring boot using OAuth [LDAP/ Social Login]. Application has some public pages and some protected pages. The requirement is we want some contents on public pages based on authenticated users. The issue is once we login in one application and visit the public page of other application, the user principal is not available on public pages, unless we visit one of the protected pages of same application. Any suggestion/ sample to achieve this, would be helpful here. Below is my code for resource server.
public class SocialApplication extends WebSecurityConfigurerAdapter {
#Autowired
CustomLdapAuthoritiesPopulator ldapAuthoritiesPopulator;
#Autowired
CustomLogoutSuccessHandler customLogoutSuccessHandler;
#RequestMapping({ "/user", "/me" })
public Map<String, String> user(Principal principal) {
Map<String, String> map = new LinkedHashMap<>();
map.put("name", principal.getName());
return map;
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/page1Prv");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**").authorizeRequests().antMatchers("/login", "/index**", "/webjars/**").permitAll()
.anyRequest().authenticated().and().authorizeRequests().anyRequest().fullyAuthenticated().and()
.formLogin().loginPage("/login").defaultSuccessUrl("/").and().logout()
.logoutSuccessHandler(customLogoutSuccessHandler).permitAll().and().csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and()
.addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);
//.userDetailsService(userDetailsService);
http.httpBasic().and().authorizeRequests().anyRequest().authenticated().and().csrf().disable();
}
#Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.ldapAuthentication()
.contextSource()
.url("ldap://localhost:10389/dc=example,dc=com").managerDn("uid=admin,ou=system")
.managerPassword("secret").and()
.ldapAuthoritiesPopulator(ldapAuthoritiesPopulator)
.userSearchBase("ou=users").userSearchFilter("(cn={0})");
}
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/me").authorizeRequests().anyRequest().authenticated();
}
}
public static void main(String[] args) {
SpringApplication.run(SocialApplication.class, args);
}
}
I returned the Principal object from user(). see below code, and it solved my problem.
#RequestMapping({ "/user", "/me" })
public Principal user(Principal principal) {
return principal;
}

Custom Authentication provider with Spring Security and Java Config

How can I define a custom Authentication provider by using Spring Security with Java Configurations?
I would like to perform a login checking credentials on my own database.
The following does what you need (CustomAuthenticationProvider is your implementation which needs to be managed by Spring)
#Configuration
#EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private CustomAuthenticationProvider customAuthenticationProvider;
#Override
protected void configure(HttpSecurity http) throws Exception {
/**
* Do your stuff here
*/
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
}
As shown on baeldung.com, define your authentication provider as follow:
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
if (shouldAuthenticateAgainstThirdPartySystem(username, password)) {
// use the credentials
// and authenticate against the third-party system
return new UsernamePasswordAuthenticationToken(
name, password, new ArrayList<>());
} else {
return null;
}
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(
UsernamePasswordAuthenticationToken.class);
}
}
and following code is corresponding java config:
#Configuration
#EnableWebSecurity
#ComponentScan("org.project.security")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private CustomAuthenticationProvider authProvider;
#Override
protected void configure(
AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and()
.httpBasic();
}
}

Resources