How to set redirect url after success login using Social Providers - spring

I need change the redirect url when my user is succefull logged in using some of Spring Social Providers, like Twitter in this case.
I'm getting in every set***Url("") a null pointer exception
Some times setting this don't work too
I tried so far setting:
public ProviderSignInController signInController(ConnectionFactoryLocator connectionFactoryLocator,
UsersConnectionRepository usersConnectionRepository) {
ProviderSignInController providerSignInController = new ProviderSignInController(connectionFactoryLocator,
usersConnectionRepository,
new CSignInAdapter(requestCache()));
providerSignInController.setPostSignInUrl("/home");
providerSignInController.setApplicationUrl("localhost:8080/home");
return providerSignInController;
}
I tried each one of setPostSignInUrl and setApplicationUrl, separately.
Also tried:
#Bean
public ConnectController connectController(ConnectionFactoryLocator connectionFactoryLocator,
ConnectionRepository connectionRepository) {
ConnectController connectController = new ConnectController(connectionFactoryLocator, connectionRepository);
connectController.addInterceptor(new TweetAfterConnectInterceptor());
connectController.setApplicationUrl("/home");
return connectController;
}
I'm using Spring Social showcase with Security as base to do this.
In case of need I'm posting the HttpSecurity configuration:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.loginPage("/signin")
.loginProcessingUrl("/signin/authenticate")
.failureUrl("/signin?param.error=bad_credentials")
.defaultSuccessUrl("/home")
.and()
.csrf()
.and()
.logout()
.logoutUrl("/signout")
.deleteCookies("JSESSIONID")
.and()
.authorizeRequests()
.antMatchers("/admin/**", "/favicon.ico", "/resources/**", "/auth/**", "/signin/**", "/signup/**",
"/disconnect/facebook").permitAll()
.antMatchers("/**").authenticated()
.and()
.rememberMe()
.and()
.apply(new SpringSocialConfigurer());
}

Try this:
private SpringSocialConfigurer getSpringSocialConfigurer() {
SpringSocialConfigurer config = new SpringSocialConfigurer();
config.alwaysUsePostLoginUrl(true);
config.postLoginUrl("/home");
return config;
}
Then change your configure method:
.apply(getSpringSocialConfigurer());

For Spring Social, you can configure the post login URL to a default URL, such as "/home".
But under certain circumstances, you would like to direct the user to a different URL. In order to dynamically change the redirect URL after successful login, you can simply return a String representing any URL you desire in the signIn method of your SignInAdapter implementation class:
import org.springframework.social.connect.web.SignInAdapter;
public class SocialSignInAdapter implements SignInAdapter {
public String signIn(String localUserId, Connection<?> connection, NativeWebRequest request) {
boolean flag = true;
if (flag) {
return "/a_different_url";
}
return null; // Default, which means using the default post login URL
}
}
I verified this using Spring Social version 1.1.0.RELEASE

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");
}
})
}

SAML with Spring security anonymousUser

We have to implement SSO using SAML in SpringBoot. I have achieved to redirect the user to the identity provider login page and make the login. The problem is that after the login, when I try to get the user info with SecurityContextHolder.getContext().getAuthentication() I get anonymousUser, and not the logged user data.
Here is my SecurityConfig
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.csrf().and()
.authorizeRequests()
.antMatchers("/saml/**).permitAll()
.anyRequest().authenticated()
.and()
.apply(saml())
.userDetailsService(samlUserDetailsServiceImpl)
.serviceProvider()
.protocol("http")
.hostname("localhost:8080")
.basePath("/")
.keyStore()
.storeFilePath("classpath:metadata/samlKeystore.jks")
.keyPassword(keystorePass)
.keyname(keystoreAlias)
.and()
.and()
.identityProvider()
.metadataFilePath("classpath:metadata/idp.xml")
.discoveryEnabled(false)
.and()
.and();
And the implementation of SAMLUserDetailService
#Service
public class SamlUserServiceImpl implements SAMLUserDetailsService {
#Override
public Object loadUserBySAML(SAMLCredential credential) {
String userID = credential.getNameID().getValue();
GrantedAuthority userAuthority = new SimpleGrantedAuthority("ROLE_GESTOR");
return new User(userID, "DUMMY", Collections.singletonList(userAuthority));
}
I have debugged the code and in the SAMLUserDetailsService implementation I receive the user data after logging.
Also, is there a way to indicate the redirection url when the user has logged? Now it redirects to same url.
Thanks in advance

Prevent Spring from creating new session if authentication fails

With the folowing code a new WebSession is created each time someone accesses my site. The state of the WebSession is set to NEW containing no attributes. This session is never deleted for some reason.
#Bean
public SecurityWebFilterChain securityWebFilterChainCatchAll(ServerHttpSecurity http) {
return http
.csrf().disable()
.authorizeExchange()
.pathMatchers("/", "/static/**")
.permitAll()
.anyExchange()
.denyAll()
.and()
.exceptionHandling()
.authenticationEntryPoint(this::returnPage)
.accessDeniedHandler(this::returnPage)
.and()
.formLogin().disable()
.httpBasic().disable()
.build();
}
private Mono<Void> returnPage(ServerWebExchange exchange, RuntimeException denied) {
Resource indexHtml = new ClassPathResource("/static/index.html");
return ok().contentType(MediaType.TEXT_HTML).syncBody(indexHtml).flatMap(d -> d.writeTo(exchange, new HandlerStrategiesResponseContext(HandlerStrategies.withDefaults())));
}
class HandlerStrategiesResponseContext implements ServerResponse.Context
{
private final HandlerStrategies strategies;
HandlerStrategiesResponseContext(HandlerStrategies strategies) {
this.strategies = strategies;
}
#Override
public List<HttpMessageWriter<?>> messageWriters() {
return this.strategies.messageWriters();
}
#Override
public List<ViewResolver> viewResolvers() {
return this.strategies.viewResolvers();
}
}
This is a catchall ServerHttpSecurity I have more specific configuration for my /api endpoint but they are working as expected when the WebSession is set in STARTED state and the attribute of SPRING_SECURITY_CONTEXT.
I have two questions regarding this.
What does it mean for WebSession to be in NEW state and why is that
not deleted, only STARTED state is deleted.
What do I need to change to either not creating any session or make sure the sessions created are deleted when expired.

Spring security 5 oauth2 login

I have a spring mvc web application that i want protect with springs security 5 Oauth2, the application successfully redirect to google for authentication, but the problem is that it keeps redirection back to the consent page just immediately after the user selects account from that consent page.
bellow is my relevant configuration.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint())
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.and()
.addFilterAfter(oauth2ClientContextFilter, ExceptionTranslationFilter.class)
.addFilterBefore(oauth2ClientAuthenticationProcessingFilter(), FilterSecurityInterceptor.class)
.anonymous()
.disable();
}
#Bean
public OAuth2ProtectedResourceDetails authorizationCodeResource() {
logger.info("authorizationCodeResource");
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
details.setId("google");
details.setClientId(environment.getProperty("google.clientId"));
details.setClientSecret(environment.getProperty("google.clientSecret"));
details.setUserAuthorizationUri(environment.getProperty("google.userAuthorizationUri"));
details.setAccessTokenUri(environment.getProperty("google.accessTokenUri"));
details.setAuthenticationScheme(AuthenticationScheme.query);
details.setClientAuthenticationScheme(AuthenticationScheme.form);
details.setPreEstablishedRedirectUri(environment.getProperty("google.reDirectURI"));
details.setUseCurrentUri(false);
details.setScope(new ArrayList<>(Arrays.asList("openid")));
return details;
}
#Bean
public OAuth2ClientAuthenticationProcessingFilter oauth2ClientAuthenticationProcessingFilter() {
logger.info("oauth2ClientAuthenticationProcessingFilter");
OAuth2RestOperations restTemplate = new OAuth2RestTemplate(authorizationCodeResource(), oauth2ClientContext);
OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter(
environment.getProperty("google.callbackURI"));
filter.setRestTemplate(restTemplate);
filter.setTokenServices(googleUserInfoTokenServices());
return filter;
}
#Bean
#Description("Google API UserInfo resource server")
public GoogleUserInfoTokenServices googleUserInfoTokenServices() {
logger.info("googleUserInfoTokenServices");
GoogleUserInfoTokenServices userInfoTokenServices = new GoogleUserInfoTokenServices(
environment.getProperty("google.userInfoUri"),
environment.getProperty("google.clientId"));
return userInfoTokenServices;
}
#Bean
public AuthenticationEntryPoint authenticationEntryPoint() {
logger.info("authenticationEntryPoint");
return new LoginUrlAuthenticationEntryPoint(environment.getProperty("google.callbackURI"));
}
Someone please help me. i can provide any addition details that you may require

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()
;

Resources