Spring Security: How to get checkbox value from login page in my controller? - spring

How to I get the value of the check box in my loginpage?
In my Jsp I have a remember me check box.
<form:form action="${pageContext.request.contextPath}/amPostLogin" method="POST" modelAttribute="userLogin">
<form:input type="text" path="username" id="username" placeholder="username"required="required" autofocus="autofocus"/>
<form:input type="password" path="password" id="password" placeholder="password" required="required"/>
<br><form:checkbox label="Remember Me" path="isRemember" />
<br><form:checkbox label="Auto Login" path="isAutoLogin"/>
<form:button class="login-button" >Login</form:button>
</form:form>
In my Spring Security I have:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/am*")
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login_AM")
.loginProcessingUrl("/amPostLogin")
.failureUrl("/login_AM?error=true")
.defaultSuccessUrl("/amChatPage")
.and()
.logout()
.logoutUrl("/amLogout")
.logoutSuccessUrl("/logoutSuccessful_AM")
.and()
.exceptionHandling()
.accessDeniedPage("/am403")
.and().httpBasic()
.and().csrf().disable();
}
Now I want to get the values of AutoLogin and RememberMe in my controller.
How do I do that?
I tried creating a controller for "/amPostLogin" but for some reason it doesn't get inside the controller. How can I get the value of those checkbox in my controller? Please someone help me. Thank you.
ANSWER
Instead of getting the value of checkbox in the controller, I created an AuthenticationSuccessHandler and get the values there.
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
boolean isRemember = Boolean.parseBoolean(request.getParameter("isRemember"));
boolean isAutoLogin = Boolean.parseBoolean(request.getParameter("isAutoLogin"));
response.setStatus(HttpServletResponse.SC_OK);
response.sendRedirect("amChatPage");
}

If you are using spring mvc your login jsp needs some changes .
1)You login page action should be mapped to j_spring_security_check.htm, spring's UsernamePasswordAuthenticationFilter.java intercepts this url for authentication.
2)Your username and password should be mapped to is j_username and j_password , this above filter expects these fields to be set, you can check the source code.
3)You also need to provide an authentication provider in context.xml
4)You need to define lgtAuthenticationFailureHandler and lgtAuthenticationsuccessHandler. From lgtAuthenticationsuccessHandler you can direct to your home page of application.
This is the login part.You can refer many sites for login authentication in spring.
For cookie part,
what you can do is on click of remember me checkbox , you can write a javascript that will create a remember me cookie with username in it and all other parameters like expiry n all.
when next time the page loads you can write a onload javascript funtion where you can check if remember me cookie exists and based in that you can populate username and tick your remember me checkbox.
This is how i have implemented so you can try this.

Related

Choice between form login and OAuth2 login with Spring Security

I want to implement a simple app that enables users to log in with a local account or to register a new account or to login with OAuth2 - e.g. facebook. For the users which chose Facebook I would like to automatically create a local account and log them in with that account.
As far as I understand Spring Social is dead (it would be really helpful if this is mentioned on the home page of the project, because it would save efforts for people like me who invested in learning spring social).
The other thing that I understand is that "OAuth2 and OIDC are now first-class citizens in the Spring Boot and Spring Security ecosystems." Seems that the right way to go is to use Spring Security 5 with its first-class support of OAuth2!
So... let's go. My application.yaml:
spring:
security:
oauth2:
client:
registration:
facebook:
client-id: senko
client-secret: topsecret
The security configuration:
#Override
protected void configure(HttpSecurity http) throws Exception {
// for the ant pattern matcher syntax, please check:
// https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/AntPathMatcher.html
http
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login/authenticate")
.failureUrl("/login?param.error=bad_credentials")
.successForwardUrl("/home")
.and()
.logout()
.logoutUrl("/logout")
.deleteCookies("JSESSIONID").
and()
.authorizeRequests()
.antMatchers("/login**").permitAll()
.antMatchers("/**").authenticated().
and().
oauth2Login().
loginPage("/login");
}
#Override
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(
new BCryptPasswordEncoder());
}
My user service uses local storage backed by MySQL. The login form in short (thymeleaf):
Login:
<form id="signin" th:action="#{/login/authenticate}" method="post">
<input id="login" name="username" type="text" size="25"></input>
<input id="password" name="password" type="password" size="25"></input>
<button type="submit">Login In</button>
</form>
Or...:
<a th:href="#{/oauth2/authorization/facebook}">Sign in with Facebook</a>
So far I'm able to login with local account. I'm also able to login with Facebook. What I miss here is the part where I should create a local user account after the successful Facebook login. What is the correct way to implement that? I'm totally clueless. What I've tried so far is to search in google and to read the code of OAuth2LoginAuthenticationProvider. Any help will be appreciated.
UPDATE: I'm exploring if implementing an AuthenticationSuccessHandler is a proper option...
You can register a custom bean (OAuth2UserService) that will automatically replace the default configuration. Actually the example below just delegates to an implementation from the default configuration but allows to extend / add additional logic (in this example to process a user).
#Bean
public OAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService() {
DefaultOAuth2UserService service = new DefaultOAuth2UserService();
return request -> {
OAuth2User user = service.loadUser(request);
System.out.println("User attributes: " + user.getAttributes()); // can be converted and saved
return user;
};
}

Logout with oauth2 when using google

In a spring boot 2 web site , user can decide to log via email/password (after created a account) or use facebook/google logi (oauth2)
Actually
user x connect via google... log out
user y try to connect via google but use user x session..
Logout is not done via google...
I would like logout support this use case
User x connect via google, logout.
User y, click to connect to google, need to enter user/password (don't want to connect via precedant user)
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/oauth_login", "/loginFailure", "/", "/logout")
.permitAll()
.anyRequest()
.authenticated()
.and()
.oauth2Login()
.loginPage("/oauth_login")
.authorizationEndpoint()
.baseUri("/oauth2/authorize-client")
.authorizationRequestRepository(authorizationRequestRepository())
.and()
.tokenEndpoint()
.accessTokenResponseClient(accessTokenResponseClient())
.and()
.defaultSuccessUrl("/loginSuccess")
.failureUrl("/loginFailure")
.and()
.logout()
.logoutSuccessUrl("/")
.invalidateHttpSession(true);
}
If I remove .csrf().disable(), I get a 403 error. Don't understand why
html log out
Logout
<form id="logoutForm" action="/logout" method="post">
<input hidden type="submit" value="Sign Out"/>
</form>
Edit
seem to have a lot of thread with this kind of error...
like this one...
google account logout and redirect
seem like a token issue.
so just dangerous to use oauth on a public computer...

SpringBoot 2.1.3 Security multiple available login page for first authentication

I'm developing a SpringBoot 2.1.3 + Thymeleaf 3 + Tomcat 8 WebApp. I have implemented Spring Security and all works well. Now I have a little problem because I want to realize two form login page, one for backoffice users and other one for all others users.
I don't wanna put both form in the same page, and like to create a page with a simple form for backoffice users and a link that redirect to another page (with another form) for customer users.
I have read some and I have found just a way to Ordering the WebSecurityConfigurerAdapter and creating multiple entry point but this way, I can log in with page with order 1 and then I can go the the other form page. It'isnt what I want to do.
Do you know if there is a way to do this??
Thank you
I found a way and it is pretty simple. I have configured the WebSecurityConfigurerAdapter as follow:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login-procout").permitAll() // login for furnishers
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login-officers") // default login page
.permitAll()
.successHandler(customAuthenticationSuccessHandler())
.and()
.logout()
.permitAll();
http.csrf().disable();
}
Then I create two html page login-officers.html and login-procout.html referred by Controller as follow:
#Controller
public class MyController {
#GetMapping("/login-officers")
public String loginOfficers() {
return "login-officers";
}
#GetMapping("/login-procout")
public String loginProcout() {
return "login-procout";
}
}
And in both page I have default Spring Security Form:
<form action="" th:action="#{/login}" method="post">
<input type="text" name="username" id="username" placeholder="Username"/>
<input type="password" name="password" id="password" placeholder="Password"/>
<input type="submit" id="login" value="Log In" />
</form>
I don't know if is the right way to do but it works.

Spring Security 4 and JSF 2 integration

Is there a way to integrate Spring Security 4 (Mainly for managing user access levels and which views they can access) and JSF 2?
I found this neat thing which allows you to mix both Spring Boot, and JSF 2 with PrimeFaces 5. Great stuff. I want to see if you can kick it up another level.
Normally you would configure Spring Security for Spring MVC like so:
WebSecurityConfig.java
#Configuration
#EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("Zyst").password("password").roles("USER");
}
}
And then those would as far as I know, do correct me if I'm mistaken, look in your MvcConfig to see what it actually means by "/home" and the like:
MvcConfig.java
#Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/home").setViewName("home");
registry.addViewController("/").setViewName("home");
registry.addViewController("/hello").setViewName("hello");
registry.addViewController("/login").setViewName("login");
}
}
However, I've been googling for a few hours and cannot really find a conclusive answer how to configure Spring Security for JSF. Can you implement your front end using JSF and then make that managed by Spring Security, so, for example Links, ie: localhost:8080/home instead of localhost:8080/home.xhtml are properly managed and served? And so that user levels defined in WebSecurityConfig.java can only access pages relevant to themselves.
From what I've (briefly) investigated it might not be possible due to Faces and Mvc being different technologies that don't particularly play well together. However, if possible I'd like to make sure of whether it's possible or not.
And if it IS possible, can you provide either a working example, or a link to somewhere that goes more in depth? I did google quite a bit but it's 100% possible I ended up missing something.
Any and all answers are greatly appreciated.
There's no problem in using Spring Boot, Spring Security, JSF and Spring Core all together, in the end, JSF views are resolved as urls and that's what you work in Spring Security with. That's an example for the configuration in my own application, which I've pruned a bit to minimize the code amount. The code is self-explanatory:
#Configuration
#EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
// Have to disable it for POST methods:
// http://stackoverflow.com/a/20608149/1199132
http.csrf().disable();
// Logout and redirection:
// http://stackoverflow.com/a/24987207/1199132
http.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.invalidateHttpSession(true)
.logoutSuccessUrl(
"/login.xhtml");
http.authorizeRequests()
// Some filters enabling url regex:
// http://stackoverflow.com/a/8911284/1199132
.regexMatchers(
"\\A/page1.xhtml\\?param1=true\\Z",
"\\A/page2.xhtml.*")
.permitAll()
//Permit access for all to error and denied views
.antMatchers("/500.xhtml", "/denied.xhtml")
.permitAll()
// Only access with admin role
.antMatchers("/config/**")
.hasRole("ADMIN")
//Permit access only for some roles
.antMatchers("/page3.xhtml")
.hasAnyRole("ADMIN", "MANAGEMENT")
//If user doesn't have permission, forward him to login page
.and()
.formLogin()
.loginPage("/login.xhtml")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/main.xhtml")
.and().exceptionHandling().accessDeniedPage("/denied.xhtml");
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
//Configure roles and passwords as in-memory authentication
auth.inMemoryAuthentication()
.withUser("administrator")
.password("pass")
.roles("ADMIN");
auth.inMemoryAuthentication()
.withUser("manager")
.password("pass")
.roles("MANAGEMENT");
}
}
Of course, this code works with *.xhtml suffixed urls, as they're served by the JSF Servlet. If you want to avoid this suffix, you should use a url rewriting tool as Prettyfaces. But that's another story that has already been widely discussed in StackOverflow.
Also, remember to target your login form to the configured login processing url to let Spring Security handle the authentication and redirection to your main page. What I usually do is to use a non-JSF form and apply the Primefaces styles on it:
<form id="login_form" action="#{request.contextPath}/login" method="post">
<p>
<label for="j_username" class="login-form-tag">User</label> <input
type="text" id="username" name="username" class="ui-corner-all"
required="required" />
</p>
<p>
<label for="j_password" class="login-form-tag">Password</label>
<input type="password" id="password" name="password"
class="ui-corner-all" required="required" />
</p>
<p>
<button type="submit"
class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only">
<span class="ui-button-text">Login</span>
</button>
</p>
</form>
See also:
Spring and JSF integration
Spring Boot JSF Integration

Spring Rest Service - Invalid CSRF token when I attempt to login

I have a Spring MVC REST service, with Spring Security (3.2.5.RELEASE) enabled. When I turn on #EnableWebMvcSecurity, a login form is automatically generated for me at http://localhost:8080/login. If I use this form to login, everything works just fine.
The problem occurs when I attempt to login by sending a POST request directly. In my post request, I provide the username and password. I also include the http header 'X-CSRF-TOKEN' and for the header value, I use the JSESSIONID that I see has been generated in a cookie. But when I send this POST request, I get back the following result:
HTTP Status 403 - Invalid CSRF Token '29F5E49EFE8D758D4903C0491D56433E'
was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.
What am I doing wrong? Am I providing the wrong token value? What is this JSESSIONID? If I don't enter a value for this header, or omit the header all together, it tells me "Null CSRF token found".
Below is my Spring Security configuration:
#Configuration
#EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/secure/**").authenticated()
.and()
.formLogin()
.usernameParameter("username")
.passwordParameter("password")
.and()
.logout()
.and()
.httpBasic()
.and()
.csrf();
}
}
I'd really appreciate any help! Thanks in advance!
(1) Include the CSRF token within all your AJAX requests.
$(function () {
var token = $('#logoutform>input').val();
var header = $('#logoutform>input').attr('name');
$(document).ajaxSend(function(e, xhr, options) {
xhr.setRequestHeader('X-CSRF-TOKEN', token);
});
});
(2) Simple request .
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
You need to send the csrf token when you submit the login form. Please add the below line in the HTML form:
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
you need <meta name="_csrf" content="${_csrf.token}"/> , https://spring.io/blog/2013/08/21/spring-security-3-2-0-rc1-highlights-csrf-protection/#ajax-requests
or if you are using thymeleaf <meta name="_csrf" th:content="${_csrf.token}" />

Categories

Resources