keycloak Spring Security : Unable to login with Bearer token as null - spring

I have integrated the Keylock with Spring boot using #KeycloakConfiguration in SecurityConfig Class,
#KeycloakConfiguration
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
// configureGlobal() tasks the SimpleAuthorityMapper to make sure roles are not
// prefixed with ROLE_.
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
// keycloakConfigResolver defines that we want to use the Spring Boot properties
// file support instead of the default keycloak.json.
#Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
// we are permitting all here but we are gonna have method level
// pre-authorization
#Override protected void configure(HttpSecurity http) throws Exception {
super.configure(http); http.cors().and().csrf().disable()
.authorizeRequests().antMatchers("/admin**").hasAnyRole("admin")
.anyRequest().permitAll();
}
// we configure to accepts CORS requests from all and any domains
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*").allowedMethods("GET", "POST", "PUT", "DELETE");
}
};
}
#PostMapping("/login")
public #ResponseBody AuthToken login(#RequestBody LoginForm form) {
Collection<SimpleGrantedAuthority> authorities =
(Collection<SimpleGrantedAuthority>) SecurityContextHolder
.getContext().getAuthentication().getAuthorities();
AuthToken authToken = authService.login(form);
authToken.setAuthorities(authorities);
return authToken;
}
and I am able to log in without a Bearer token and with an empty Bearer token.
I have created a login page in angular,
and from that, I am passing the bearer token is null.
I am getting
status": 401,
“error”: “Unauthorized”
and there are no security logs on eclipse.
Thanks and Regards

Put this into SecurityConfig
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
// All of Spring Security will ignore the requests
.antMatchers("/login");
}

Related

spring boot API + security +ldap

I want to achieve LDAP verification without form login, But not sure how to achieve it.
EDITED: I have a custom POST API /login which accept userId and password and validate it and creates a session cookies/Token.
Few doubts:
how to point to custom login URL endpoint?
How internally the form login used to validate the cookie once we successfully validated the credentials? How to achieve the same with custom login endpoint?
Do i have to change something in CRSF?
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private LdapProperties ldapProperties;
#Bean
public LdapAuthenticationProvider
authenticationProvider(final LdapAuthenticator authenticator) {
return new LdapAuthenticationProvider(authenticator);
}
#Bean
public BindAuthenticator authenticator(final BaseLdapPathContextSource contextSource) {
final BindAuthenticator authenticator = new BindAuthenticator(contextSource);
authenticator.setUserDnPatterns(new String[] {
ldapProperties.getUserDnPatterns() });
return authenticator;
}
#Override
public void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.ldapAuthentication().userSearchFilter(ldapProperties.getSearchFilter())
.contextSource(contextSource());
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.formLogin().and()
.authorizeRequests()
.anyRequest().fullyAuthenticated().and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login");
}
#Override
public void configure(final WebSecurity web) throws Exception {
web.debug(true);
}
#Bean
public LdapContextSource contextSource() {
final LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl(ldapProperties.getUrl());
contextSource.setBase(ldapProperties.getBase());
contextSource.setUserDn(ldapProperties.getUserDn());
contextSource.setPassword(ldapProperties.getUserDnPaswrd());
contextSource.setPooled(true);
contextSource.afterPropertiesSet();
return contextSource;
}
#Bean
public LdapTemplate ldapTemplate() {
final LdapTemplate ldapTemplate = new LdapTemplate(
contextSource());
ldapTemplate.setIgnorePartialResultException(true);
return ldapTemplate;
}
}

Spring boot + LDAP form login, logout and validating the token after login

I am integrating spring boot with LDAP to Authenticate a user. So that only authenticated users can only access the API.
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
LdapAuthenticationProvider authenticationProvider(final LdapAuthenticator authenticator) {
return new LdapAuthenticationProvider(authenticator);
}
#Bean
BindAuthenticator authenticator(final BaseLdapPathContextSource contextSource) {
final BindAuthenticator authenticator = new BindAuthenticator(contextSource);
authenticator.setUserDnPatterns(new String[] {
"xx" });
return authenticator;
}
#Override
public void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.ldapAuthentication().userSearchFilter("(sAMAccountName={0})")
.contextSource(contextSource());
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.formLogin().and()
.authorizeRequests()
.anyRequest().fullyAuthenticated().and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login");
}
#Override
public void configure(final WebSecurity web) throws Exception {
web.debug(true);
}
#Bean
LdapContextSource contextSource() {
final LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl("xx);
contextSource.setBase("xx");
contextSource.setUserDn("xx");
contextSource.setPassword("xx");
contextSource.setPooled(true);
contextSource.afterPropertiesSet();
return contextSource;
}
#Bean
public LdapTemplate ldapTemplate() {
final LdapTemplate ldapTemplate = new LdapTemplate(
contextSource());
ldapTemplate.setIgnorePartialResultException(true);
return ldapTemplate;
}
}
I am using the inbuild form login.
Question
Who (which class) is responsible to create a success token and where is it stored and in successive calls how is it validated?
Now I am only redirecting the unauthenticated calls to the login page due to this it giving 200 success responses, How to override this and send 401
Edited:
I have one specific question
If there is no token, the user is stored in the session -> how subsequent requests are validated. Which all classes are used

Empty response from springboot server with token keycloak

I have a Springboot server and a keycloak server, if I get the token from keycloak and I give it to Springboot it gives to me a response but EMPTY!
These are my configurations:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(jsr250Enabled = true)
public class KeycloakSecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.requiresChannel().anyRequest().requiresSecure();
http.authorizeRequests().anyRequest().permitAll();
http.csrf().disable();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
#Bean
public KeycloakConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
}
Here the properties:
keycloak.realm=***
keycloak.auth-server-url=http://localhost:8080/auth
keycloak.ssl-required=external
keycloak.resource=***
keycloak.credentials.secret=***
keycloak.use-resource-role-mappings=true
keycloak.bearer-only=true
This is the result obtained from postman:

trouble connecting Angular 10 with Spring security to use custom login page

I have been working on a web application using Spring boot and spring security with frontend controlled by angular 10. I have implemented backend for security and created a login page also. But, on running on local host it is throwing an error
blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I have been banging my head all day long to resolve this error but could not find the solution.
I have attached my code below for reference
Controller
#RestController
#RequestMapping("/user")
public class UserController {
#Autowired
AuthenticationManager authenticationManager;
#PostMapping("/login")
public boolean login(#RequestBody loginDetails data) {
try {
String username = data.getUsername();
System.out.println("Checking...");
System.out.println(data.getUsername());
System.out.println(data.getPassword());
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, data.getPassword()));
// String token = jwtTokenProvider.createToken(username,
// this.users.findByEmail(username).getRoles());
System.out.println("abcdefg");
Map<Object, Object> model = new HashMap<>();
model.put("username", username);
// model.put("token", token);
/* return true; */
} catch (AuthenticationException e) {
/*
* throw new BadCredentialsException("Invalid email/password supplied");
*/
return false;
}
return true;
}
WebSecurityConfiguration
#EnableWebSecurity
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Qualifier("userDetailsService")
#Autowired
private UserDetailsService userDetailsService;
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/user/save","/user/login",
"/admin/**").permitAll().anyRequest().authenticated().and().csrf()
.disable().formLogin().permitAll().and().logout().permitAll();
http.cors();
}
#Bean
public AuthenticationManager customAuthenticationManager() throws Exception {
return authenticationManager();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
}
AngularRequestcode
public doLogin(){
this.userLogin.username=this.loginForm.get("username").value;
this.userLogin.password=this.loginForm.get("password").value;
console.log(this.userLogin);
return this.http.post<any>("http://localhost:8080/user/login",this.userLogin).subscribe((response) => {
if (response.status === 200) {
console.log('login successfully');
} else {
console.log('galat');
}
}
);
}
First of all, try change to:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().cors().and()
.authorizeRequests().antMatchers("/user/save", "/user/login",
"/admin/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().permitAll()
.and().logout().permitAll();
}
CORS it's browser check if you have response with: Access-Control-Allow-Origin: http://localhost:4200 or no: No 'Access-Control-Allow-Origin' header is present on the requested resource.;
Change http://localhost:4200 to your front-end url;
And add to your WebSecurityConfig:
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:4200")
.allowedMethods("*");
}
and: implements WebMvcConfigurer
Response without error:
Response with error. No Access-Control-Allow-Origin:

Spring security manually authentication not working

i'm changing an existing app with spring boot, this app not use spring security for authentication, the authentication is a method in a controller, so i want use spring security and i'm trying to use manually authentication in spring security but not working, below you can see the code:
Controller:
#Autowired
#Qualifier(BeanIds.AUTHENTICATION_MANAGER)
private AuthenticationManager authenticationManager;
#PostMapping(value = "/authenticate")
public ResponseEntity<UsuarioRequest> login(#RequestBody UsuarioRequest request, HttpServletRequest servletRequest)
throws AppException {
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(request.getUsulog(), request.getUsupass());
Authentication authentication = authenticationManager
.authenticate(authToken);
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(authentication);
UsuarioRequest usuario = usuarioFacadeAPI.findByUsername(request.getUsulog());
return new ResponseEntity<UsuarioRequest>(usuario, HttpStatus.OK);
}
Security Config:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private SiscoAuthenticationProvider siscoAuthenticationProvider;
#Autowired
public SecurityConfig(SiscoAuthenticationProvider siscoAuthenticationProvider) {
super();
this.siscoAuthenticationProvider = siscoAuthenticationProvider;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(siscoAuthenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin().disable();
http.csrf().disable();
http.authenticationProvider(siscoAuthenticationProvider).authorizeRequests()
.antMatchers("/login/api/**", "/zona/api/**", "/rol/api/**").permitAll()
.anyRequest().authenticated();
}
#Bean(name = BeanIds.AUTHENTICATION_MANAGER)
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
}
CustomAuthenticationProvider:
#Component
public class SiscoAuthenticationProvider implements AuthenticationProvider{
private static final String ROLE = "ROLE_";
#Autowired
private UsuarioServiceAPI usuarioServiceAPI;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UsernamePasswordAuthenticationToken token = null;
try {
UsuarioRequest request = usuarioServiceAPI.authenticate(authentication.getPrincipal().toString(), authentication.getCredentials().toString());
List<RolRequest> rols = request.getRoles();
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (RolRequest rol : rols) {
authorities.add(new SimpleGrantedAuthority(ROLE+rol.getRolnom()));
}
token = new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), authorities);
} catch (AppException e) {
String message = BundleLoader.getMessage(e.getDetails().getBundle(), e.getDetails().getKey(),
LocaleContextHolder.getLocale());
throw new UsernameNotFoundException(message, e);
}
return token;
}
#Override
public boolean supports(Class<?> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
}
For the permitAll config no problem occurred, but any other request returns 403 error code even after authentication is success, i suspect that in the controller the SecurityContextHolder not update the authentication, by this the user is always anonymous.
i found a solution for the problem, i changed the Spring Security Config class, specifically the method configure(HttpSecurity http) code below:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin().disable();
http.csrf().disable();
http.authenticationProvider(siscoAuthenticationProvider).authorizeRequests()
.antMatchers("/login/api/**", "/zona/api/**", "/rol/api/**").not().authenticated()
.anyRequest().not().anonymous();
}
the prev config was have problems, with permitAll method and with authenticated method for anyRequest, changing this config for not().authenticated() and not().anonymous() in that order, i get the expected result.

Resources