Spring Security LDAP Auth from Ionic - spring

I developed a Back End with using Java Spring and I added LDAP Authentication with extending WebSecurityConfigurerAdapter. I can get authenticated from POSTMAN but I can't from Ionic.
My Spring side ;
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//TODO: add other endpoints like /events in order to permit un-authenticated users
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login**").anonymous()
.antMatchers("/resources/**").permitAll()
.antMatchers("/assets/**").permitAll()
.antMatchers("/").authenticated()
.antMatchers("/home").authenticated()
.antMatchers("/events/**").authenticated()
.and()
.formLogin()
.and()
.logout()
.permitAll()
.and()
.cors()
.and()
.csrf()
.disable();
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource()
.url("ldap://ldap.forumsys.com/dc=example,dc=com")
.and()
.userSearchFilter("(uid={0})")
.userSearchBase("ou=mathematicians")
.userDnPatterns("uid={0}");
}
Login Controller;
#RequestMapping(value = "/")
public String home() throws NamingException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String currentPrincipalName = authentication.getName();
return "hey, nice! = " + currentPrincipalName;
}
And my Postman Login;
Postman Screenshot
Lastly, my client (ionic) side auth code;
authenticate(event) {
event.preventDefault();
const data = new URLSearchParams();
data.append("username",this.state.username);
data.append("password",this.state.password);
fetch(host + "/login", {
mode: 'no-cors',
method: 'POST',
body: data,
redirect :"follow",
headers: {
'Accept': '*/*'
},
keepalive: true
})
}
But from my Ionic side, I can't get "hey, nice! = euler" response as I get from POSTMAN. I think that I handled with CORS but I didn't figure out whats the problem.

I answered my question.
I added proxy to my package.json and added credentials: "include" to post request header at front end.

Related

How do I redirect to a specific uri after Google oauth using Spring Boot

I'm implementing a server using Spring Boot. After the user do an oauth login, I want the user to go redirect to a specific uri so I can let the user register or login. The Google OAuth login seems like it is working fine but it keeps going to "/" uri. I want to user to be redirected to "/api/v1/member/oauth"
This is my Spring Security setup.
...
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.cors()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/swagger-ui/**", "/swagger-resources/**", "/v2/api-docs")
.permitAll()
.anyRequest()
.permitAll()
.and()
.oauth2Login()
.defaultSuccessUrl("/api/v1/member/oauth")
.userInfoEndpoint()
.userService(customOAuth2MemberService);
}
...
This is the OAuth service that a user is directed to. (This works fine)
#Service
#RequiredArgsConstructor
public class CustomOAuth2MemberService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
#Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) {
OAuth2UserService<OAuth2UserRequest, OAuth2User> delegate = new DefaultOAuth2UserService();
OAuth2User oAuth2User;
try {
oAuth2User = delegate.loadUser(userRequest);
} catch (OAuth2AuthenticationException e) {
throw new CustomException(OAUTH_FAIL);
}
return new DefaultOAuth2User(oAuth2User.getAuthorities(), oAuth2User.getAttributes(), "sub");
}
}
I want to get the DefaultOAuth2User which is returned from the above to this uri.
#PostMapping("/api/v1/member/oauth")
public Object registerOrLogin(DefaultOAuth2User defaultOAuth2user) {
return ResponseEntity.status(200)
.body(DefaultResponseDto.builder()
.responseCode("MEMBER_LOGIN")
.build());
}
It currently is not going to this uri and is redirected to "/".
NEW: I redirected it by having .defaultSuccessUrl() but now the DefaultOAuth2User is not sent with the redirection, causing the parameter of redirected api to be null. How do I fix this problem?
Try to use
.oauth2Login()
.defaultSuccessUrl("/api/v1/member/oauth")
this should override post-authentication behavior and redirect to the desired page after successful login. Also, there is a similar method for setting redirection URL for failed authentication .failureUrl("url").
Spring-Security AbstractAuthenticationProcessingFilter class has successfulAuthentication() methos, which defines what happens when a User is successfully authenticated. You can register your success handler and put your redirect logic there.
But here is a catch, when using OAuth2.0, we need to specify redirect-uri to which user will be landed after client receives an access-token.
If you are okay with this Oauth's redirect-uri, do not alter the redirect in success handler or if you need to redirect irrespective of that, use response.sendRedirect("/social-login-sample/some-page");
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.cors()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/swagger-ui/**", "/swagger-resources/**", "/v2/api-docs")
.permitAll()
.anyRequest()
.permitAll()
.and()
.oauth2Login()
.userInfoEndpoint()
.userService(customOAuth2MemberService)
.and()
.successHandler(
new AuthenticationSuccessHandler() {
#Override
public void onAuthenticationSuccess(
HttpServletRequest request,
HttpServletResponse response,
Authentication authentication)
throws IOException, ServletException {
// authentication.getName() : Principal Name
CustomOAuth2User oauthUser = (CustomOAuth2User) authentication.getPrincipal();
// Check if user is registered in your Database, if not, register new user
//userService.processAuthenticatedUser(oauthUser.getEmail());
// Get actual redirect-uri set in OAuth-Provider(Google, Facebook)
String redirectUri =
UriComponentsBuilder.fromHttpUrl(UrlUtils.buildFullRequestUrl(request))
.replaceQuery(null)
.build()
.toUriString();
log.info("redirectUri: {}", redirectUri);
// Ignore redirect-uri, and send user to a different page instead...
// response.sendRedirect("/social-login-sample/some-ther-page");
}
})
}

Spring Boot Login 401 unauthorized Postman

In my spring boot application I have one endpoint for login and one for signup. When signing up everything is fine, the new user is created correctly.
Then if I try to login with the just-created credentials, Postman returns a 401 Unauthorized error. These are my controller methods (first login then signup):
#PostMapping(PathConstants.LOGIN_ACTION)
#ApiOperation("Login into Helios administrational console.")
#Override
public ResponseEntity<?> autenticate(#Valid #RequestBody LoginRequest request) {
System.out.println("Login");
System.out.println("Us psw " + request.getUsername() + " " + request.getPassword());
Authentication auth = authManager
.authenticate(new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword()));
System.out.println("Auth " + auth.toString());
SecurityContextHolder.getContext().setAuthentication(auth);
String token = jwtProvider.generateToken(auth);
System.out.println("TOken " + token);
return ResponseEntity.ok(new JwtAuthResponse(token));
}
#PostMapping(PathConstants.SIGNUP_ACTION)
#ApiOperation("Signup to Helios administrational console.")
#Override
public ResponseEntity<?> register(#Valid #RequestBody SignUpRequest request) {
sysdataUserService.createNewSysdataUser(request);
return ResponseEntity.ok().body(new DashboardResponse(true, "New sysdata user registered successfully."));
}
I get on console "login" and "Us psw" with the correct data, but after
Authentication auth = authManager
.authenticate(...)
nothing is printed. I'm thinking is a problem with the authenticate method, but what problem could be? And how can I solve it? These are my security configurations:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, PathConstants.USER_AUTH +"/**", PathConstants.HELIOS+"/dashboard/**").permitAll()
.antMatchers(HttpMethod.GET, "/"+PathConstants.PROCESS_DEFINITION+"/**").permitAll()
.antMatchers(HttpMethod.POST, "/"+PathConstants.PROCESS_DEFINITION+"/**").permitAll()
.antMatchers(HttpMethod.GET, "/"+PathConstants.PROCESS_INSTANCE+"/**").permitAll()
.antMatchers(HttpMethod.POST, PathConstants.LOGIN_ACTION).permitAll()
//.anyRequest().authenticated()
.anyRequest().permitAll()
.and()
.exceptionHandling().authenticationEntryPoint(jwtAuthEntryPoint).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// custom jwt filter.
http.addFilterBefore(jwtAuthFilter(), UsernamePasswordAuthenticationFilter.class);
}
I've added .antMatchers(HttpMethod.POST, PathConstants.LOGIN_ACTION).permitAll() to try if this way it works, but still I had 401. Then I have these WebMvcConfigurations for Cors policy:
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("*")
.allowedMethods("HEAD", "OPTIONS", "GET", "POST", "PUT", "PATCH", "DELETE")
.allowedHeaders("Content-Type", "X-Requested-With", "accept", "Origin", "Access-Control-Request-Method",
"Access-Control-Request-Headers")
.exposedHeaders("Access-Control-Allow-Origin", "Access-Control-Allow-Credentials").maxAge(MAX_AGE);
//.allowCredentials(true).maxAge(MAX_AGE);
}
What is wrong?
All the other endpoints work correctly, but not login.

how to do Authentication in Spring security using custom user detail service and angular js 2 as front end

this is my security configuration file
package com.data.topic;
#EnableWebSecurity
#ComponentScan(basePackageClasses = CustomUserDetailService.class)
public class Security extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/css/**", "/index").permitAll()
.antMatchers("/js/**").permitAll()
.antMatchers("/node_modules").permitAll()
.antMatchers("/topic/**").hasRole("user")
.and()
.formLogin().loginPage("/sch_signin")
.usernameParameter("username")
.passwordParameter("password")
.successForwardUrl("/")
.failureUrl("/login-error")
.and().csrf().disable();
}
#Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsServiceBean());
}
#Override
public UserDetailsService userDetailsServiceBean() throws Exception {
return new CustomUserDetailService();
}
}
i want to know how should i send username and password using angular2 i tried this method on submit
onSubmit(){
let url="http://localhost:8080/sch_signin";
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
console.log(this.user);
this.http.post(url,JSON.stringify(this.user),options);
console.log('data submited');
}
i don't get any error and neither i get authenticated
please help me understand how spring intercept the authentication request
I got the solution after some research. I was posting the form in wrong way the right way to post a form in Angular2.
let url="http://localhost:8080/sch_signin";
let headers = new Headers({'Content-Type':'application/x-www-form-urlencoded'});
let options = new RequestOptions({ headers: headers });
this.http.post(url,body.toString(),options).subscribe((data)=>console.log(data));
First the content type should be application/x-www-form-urlencoded and second you have to send the data in request body so Spring Security can read it.

Spring Boot Authorization Basic Header Never Changes

I am attempting to setup a very basic spring boot authenticated application. I am setting the Authorization header in the client and sending it to the backend. I can verify that the client is sending the correct header.
The backend receives the header correctly on the first attempt to login. However if the login credentials are incorrect subsequent requests retain whatever the header for the intial request was (caching it or something).
I am using Redis to Cache the session. My config is as follows:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired AuthenticationEntryPoint authenticationEntryPoint;
#Autowired CsrfTokenRepository csrfTokenRepository;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.csrf()
.disable()
.authorizeRequests().antMatchers("**")
.permitAll()
.anyRequest()
.authenticated()
;
}
}
AuthenticationEntryPoint
public class AuthenticationEntryPointBean {
#Bean
AuthenticationEntryPoint authenticationEntryPoint() {
return new RestAuthenticationEntryPoint();
}
}
Any direction would be appreciated.
** Edit **
Adding cache settings
#Configuration
#EnableRedisHttpSession
public class HttpSessionConfig {
#Bean
public JedisConnectionFactory connectionFactory() {
return new JedisConnectionFactory(); // <2>
}
}
Also I am trying to invalidate cache but that doesn't seem to work
#CrossOrigin
#RequestMapping(value="/auth/login", method = RequestMethod.GET, produces="application/json")
public #ResponseBody String login(#RequestHeader(name = "authorization") String authorization, HttpSession session, HttpServletRequest request)
{
try
{
authorization = authorization.substring("Basic ".length());
String decoded = new String(Base64.getDecoder().decode(authorization),"UTF-8");
Gson gson = new Gson();
LoginRequest login = gson.fromJson(decoded,LoginRequest.class);
UserAuthenticationEntity entity = service.getSecurityContext(login).orElseThrow(() ->
new BadCredentialsException("Authentication Failed.")
);
session.setMaxInactiveInterval((int)TimeUnit.MINUTES.toSeconds(expiresInMinutes));
SecurityContextHolder.getContext().setAuthentication(new EntityContext(entity,expiresInMinutes));
String response = gson.toJson(BasicResponse.SUCCESS);
return response;
}
catch (Exception e)
{
session.invalidate();
e.printStackTrace();
throw new AuthenticationCredentialsNotFoundException("Authentication Error");
}
}
Adding the following to my web security config seemed to do the trick.
.requestCache()
.requestCache(new NullRequestCache())
I am not sure what side effects are of doing this. I picked it up off of a blog https://drissamri.be/blog/2015/05/21/spring-security-and-spring-session/
If there is any more insight into if this is good practice or bad practice I would appreciate any comments.
My final web security config looks like the following:
http
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.csrf()
.disable()
.authorizeRequests().antMatchers("**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.requestCache()
.requestCache(new NullRequestCache())
.and()
.sessionManagement()
.sessionFixation()
.newSession()
;

Problems using Spring login in REST with CORS

I am trying to implement a website using REST. My strategy to authenticate the users consist of sending a JWT token to the user in reply to a username/password combination sent via POST. The most relevant part of my security conf is shown below.
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/images/**", "/scripts/**", "/styles/**", "favicon.ico");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.exceptionHandling()
.authenticationEntryPoint(new RESTAuthenticationEntryPoint()).and()
.formLogin()
.successHandler(authenticationSuccessHandler())
.failureHandler(new SimpleUrlAuthenticationFailureHandler())
.loginProcessingUrl("/login") //Not necesary because is the default
.permitAll().and()
.authorizeRequests()
.antMatchers("/api/getStatistics").permitAll()
.anyRequest().denyAll().and()
.addFilterBefore(new JwtTokenAuthenticationFilter(jWTTokenService()), UsernamePasswordAuthenticationFilter.class);
}
#Bean
public SavedRequestAwareAuthenticationSuccessHandler authenticationSuccessHandler() {
return new RESTAuthenticationSuccessHandler(jWTTokenService());
}
#Bean
public JWTTokenService jWTTokenService() {
return new JWTTokenServiceImpl();
}
To allow the CORS access I have written the following lines in a class extending of WebMvcConfigurerAdapter
#Override
public void addCorsMappings(CorsRegistry registry){
registry.addMapping("/api/**")
.allowedOrigins("*")
.allowedHeaders("Origin", "X-Requested-With", "Content-Type", "Accept")
.allowedMethods("GET", "POST", "OPTIONS")
.allowCredentials(true).maxAge(3600);
registry.addMapping("/login")
.allowedOrigins("*")
.allowedHeaders("Origin", "X-Requested-With", "Content-Type", "Accept")
.allowedMethods("POST", "OPTIONS")
.allowCredentials(true).maxAge(3600);
}
So when I make a call to /login sending the username and password it is supposed that Spring will catch the request, will process it and then will redirect to the success or failure handler.
Well, instead of that I have gotten an 403 Forbidden response during the CORS preflight. I decide to debug the program because I thought that when I wrote formLogin(), the UsernamePasswordAuthenticationFilter create a new AntPathRequestMatcher with the value ("/login", "POST").
What I found in the debug console was the following
Request 'OPTIONS /login' doesn't match 'POST /login
Of course it does not! Some hours later trying to solve the problem I discovered that everything works if I declare a empty method /login because during the preflight Spring finds the method and then send a 200OK to the client so the client then is allowed to send a POST that is captured by the UsernamePasswordAuthenticationFilter.
#Controller
public class LoginController {
#RequestMapping(value = { "/login" }, method = RequestMethod.POST)
public void dummyLogin() {
}
}
So, my question is: Should I really declare an empty method to "cheat" during the CORS preflight or it is just that I have missed something? Because it is not so elegant to declare a dummy method when you really want to delegate the job to the UsernamePasswordAuthenticationFilter...
The problem is that org.springframework.security.web.authentication.logout.LogoutFilter and org.springframework.security.web.authenticationUsernamePasswordAuthenticationFilter do not continue with the filter chain if they handled a login/logout. And since the configuration via WebSecurityConfigurerAdapter is processed later in the chain, the CorsProcessor is never applied.
I decided to keep the old solution and use a org.springframework.web.filter.CorsFilter.
It is not necessary to have empty method to make it work. The only thing you have to do is to allow OPTIONS call on the /login URL.
.antMatchers(HttpMethod.OPTIONS, "/login").permitAll()
Ex :
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.exceptionHandling()
.authenticationEntryPoint(new RESTAuthenticationEntryPoint()).and()
.formLogin()
.successHandler(authenticationSuccessHandler())
.failureHandler(new SimpleUrlAuthenticationFailureHandler())
.loginProcessingUrl("/login") //Not necesary because is the default
.permitAll().and()
.authorizeRequests()
.antMatchers("/api/getStatistics").permitAll()
.antMatchers(HttpMethod.OPTIONS, "/login").permitAll()
.anyRequest().denyAll().and()
.addFilterBefore(new JwtTokenAuthenticationFilter(jWTTokenService()), UsernamePasswordAuthenticationFilter.class);
}

Resources