How to configure Spring 4.0 with spring boot and spring security openId - spring

I'm trying to get a Spring 4.0 boot application up and running with Spring Security OpenId. I'm using the standard way to bootstrap a Spring boot app:
#Configuration
#ComponentScan("x.y.z")
#EnableAutoConfiguration
#Import({SecurityConfig.class})
public class ServiceRegistryStart extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(ServiceRegistryStart.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
application.sources(getClass());
return application;
}
}
The SecurityConfig.class looks like this (Influenced by the "openid-jc sample project in Spring security):
#Configuration
#EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.anyRequest().authenticated()
.and()
.openidLogin()
.loginPage("/login.html")
.permitAll()
.authenticationUserDetailsService(new CustomUserDetailsService())
.attributeExchange("https://www.google.com/.*")
.attribute("email")
.type("http://axschema.org/contact/email")
.required(true)
.and()
.attribute("firstname")
.type("http://axschema.org/namePerson/first")
.required(true)
.and()
.attribute("lastname")
.type("http://axschema.org/namePerson/last")
.required(true)
.and()
.and()
.attributeExchange(".*yahoo.com.*")
.attribute("email")
.type("http://axschema.org/contact/email")
.required(true)
.and()
.attribute("fullname")
.type("http://axschema.org/namePerson")
.required(true)
.and()
.and()
.attributeExchange(".*myopenid.com.*")
.attribute("email")
.type("http://schema.openid.net/contact/email")
.required(true)
.and()
.attribute("fullname")
.type("http://schema.openid.net/namePerson")
.required(true);
}
#Bean(name = "myAuthenticationManager")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
class CustomUserDetailsService implements AuthenticationUserDetailsService<OpenIDAuthenticationToken> {
#Override
public UserDetails loadUserDetails(OpenIDAuthenticationToken token) throws UsernameNotFoundException {
return new User(token.getName(), "", AuthorityUtils.createAuthorityList("ROLE_USER"));
}
}
}
The login page looks like this:
<form id="googleLoginForm" action="/j_spring_openid_security_check" method="post">
<h1>Login</h1>
<input name="openid_identifier" type="hidden" value="https://www.google.com/accounts/o8/id"/>
<input name="openid.ns.pape" type="hidden" value="http://specs.openid.net/extensions/pape/1.0"/>
<input name="openid.pape.max_auth_age" type="hidden" value="0"/>
<p>
<input name="submit" value="Login using Google" type="submit"/>
</p>
</form>
The problem is that the "/j_spring_openid_security_check" doesn't seem to exist. I think the problem is that I ought to extend from AbstractSecurityWebApplicationInitializer when using Spring Security but for boot I should use SpringBootServletInitializer. What's the best way to combine the two? The javadoc of SpringBootServletInitializer says that it registers a filter automatically when Spring Security is detected but it doesn't seem to work in this case.

I actually managed to solve this. First off all I used Spring Boot to start an embedded container so I didn't need any WebApplicationInitializers. Secondly the post URL in the login page should point to "/login/openid" and thirdly I had to disable cross-site request forgery prevention in the security configuration using:
http.csrf().disable(). ..
in the configure method in the SecurityConfig class.

Related

Google logout doesn't work in Windows 11 only when using spring boot security

Here is my spring boot security code. The same code works fine on Windows 10 and MacOS. But it doesn't work when I use the same code in Eclipse on Windows 11. Both Chrome and Edge browser are having the same issue. The logout button just doesn't log me out. Can anyone help? Thanks.
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/**").authorizeRequests()
.antMatchers("/", "/welcome").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login()
.and()
.logout().logoutSuccessUrl("/welcome").permitAll();
}
}
<form th:action="#{logout}" method="post">
<input type="submit" value="Sign out"/><br/>
</form>

Spring MVC/Security - Users still can access login page after successful login

I am very new to Spring.
I am working with version 4.3.9.RELEASE of Spring MVC, 4.2.3.RELEASE of Spring Security.
I am using the built in login of spring with a little customization, here is my configure
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService myUserService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(myUserService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.rememberMe()
.alwaysRemember(true)
.and()
.logout()
.permitAll();
}
}
Why users can access login page after they logged in successfully? I tried to learn from the questions that are the same like mine, but none of them works with me.
This solution doesn't work with me:
<sec:authorize access="isAuthenticated()">
<% response.sendRedirect(request.getContextPath()); %>
</sec:authorize>
I am using Apache Tiles, I have is_authenticated.jsp with that part. and this is the tiles.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
"http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
<definition name="base" template="/WEB-INF/layouts/page.jsp">
<put-attribute name="pageHeader" value="/WEB-INF/layouts/page_header.jsp"></put-attribute>
<put-attribute name="pageFooter" value="/WEB-INF/layouts/page_footer.jsp"></put-attribute>
</definition>
<definition name="login" extends="base">
<put-attribute name="isAuthenticated" value="/WEB-INF/views/is_authenticated.jsp"></put-attribute>
<put-attribute name="pageBody" value="/WEB-INF/views/login.jsp"></put-attribute>
</definition>
<definition name="home" extends="base">
<put-attribute name="isAuthenticated" value=""></put-attribute>
<put-attribute name="pageBody" value="/WEB-INF/views/home.jsp"></put-attribute>
...
</tiles-definitions>
and here is page.jsp
<!DOCTYPE>
<html>
<head>
<t:insertAttribute name="isAuthenticated"></t:insertAttribute>
...
</head>
<body>
<!-- Page Layout HTML -->
<header id="pageHeader">
<t:insertAttribute name="pageHeader"></t:insertAttribute>
</header>
<main id="pageBody">
<t:insertAttribute name="pageBody"></t:insertAttribute>
</main>
...
</body>
</html>
The is_authenticated.jsp is included and rendered but it doesn' work, it does work only if I put the block inside the page.jsp itself, which looks wrong as you see, but it doesn't work when included from another jsp file.
Another solution, handling this issue from login controller, but this is not available in my case, because I didn't use any controller to handle login process.
Should I do?
The custom login controller will be more secure than the default one in Spring?
Update1
I tried to use the default login feature of spring:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService myUserService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(myUserService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin();
}
}
But I found that after successful login, user can still access login page.
So I am guessing I need to have a method in LoginController to accomplish this.
I had the same problem and I solved it by using access() method:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/login", "/signup", "/")
.access("hasRole('ANONYMOUS')")
.antMatchers("/test").access("permitAll()")
.antMatchers("/user/**").access("hasRole('ADMIN')")
.anyRequest().authenticated()
.antMatchers()
.access("hasRole('USER')").anyRequest().fullyAuthenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.successHandler(loginSuccessHandler()).permitAll()
.failureHandler(loginFailureHandler())
.and()
.logout()
.permitAll()
.logoutSuccessUrl("/");
}
private AuthenticationSuccessHandler loginSuccessHandler() {
return (request, response, authentication) ->{
response.sendRedirect("/home");
};
}
private AuthenticationFailureHandler loginFailureHandler() {
return (request, response, exception) -> {
response.sendRedirect("/");
};
}
I think I found an answer.
Since I configured configure method as this:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.rememberMe()
.alwaysRemember(true)
.and()
.logout()
.permitAll();
}
I was supposed to have addViewControllers in my implementation of WebMvcConfigurerAdapter.
So I tried to remove this method and instead create a LoginController which only have login() method for GET requests that handle the redirect if the user is authenticated.
#Controller
public class LoginController {
#RequestMapping(value="/login", method=GET)
public String login(Principal principal) {
return principal == null ? "login" : "redirect:/";
}
}

How to turn off Spring Security in Spring Boot Application

I have implemented authentication in my Spring Boot Application with Spring Security.
The main class controlling authentication should be websecurityconfig:
#Configuration
#EnableWebSecurity
#PropertySource(value = { "classpath:/config/application.properties" })
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private RestAuthenticationSuccessHandler authenticationSuccessHandler;
#Autowired
private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(
SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/logout").permitAll()
.antMatchers("/ristore/**").authenticated()
.anyRequest().authenticated()
.and()
.formLogin()
.successHandler(authenticationSuccessHandler)
.failureHandler(new SimpleUrlAuthenticationFailureHandler());
}
Since I am doing OAuth, I have AuthServerConfig and ResourceServerConfig as well. My main application class looks like this:
#SpringBootApplication
#EnableSpringDataWebSupport
#EntityScan({"org.mdacc.ristore.fm.models"})
public class RistoreWebApplication extends SpringBootServletInitializer
{
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*");
}
};
}
public static void main( String[] args )
{
SpringApplication.run(RistoreWebApplication.class, args);
}
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(RistoreWebApplication.class);
}
}
Since we are doing code consolidation, we need to turn off authentication temporarily. However, I tried the following methods and nothing seems to work. I am still getting 401 when I hit these rest api urls.
Comment out all the annotations in classes related to security including #Configuration, #EnableWebSecurity. In Spring boot Security Disable security, it was suggested at the bottom adding #EnableWebSecurity will DISABLE auth which I don't think make any sense. Tried it anyway, did not work.
Modify websecurityconfig by removing all the security stuff and only do
http
.authorizeRequests()
.anyRequest().permitAll();
Disable Basic Authentication while using Spring Security Java configuration. Does not help either.
Remove security auto config
#EnableAutoConfiguration(exclude = {
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration.class,
org.springframework.boot.actuate.autoconfigure.ManagementSecurityAutoConfiguration.class})
like what they did in disabling spring security in spring boot app. However I think this feature only works with spring-boot-actuator which I don't have. So didn't try this.
What is the correct way disable spring security?
As #Maciej Walkowiak mentioned, you should do this for your main class:
#SpringBootApplication(exclude = org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration.class)
public class MainClass {
try this
1->Comment annotation #EnableWebSecurity in your security config
//#EnableWebSecurity
2->Add these lines in your security config
spring.security.enabled=false
management.security.enabled=false
security.basic.enabled=false
What worked for me is this. Creating WebFilter and PermitAll Request Exchange and disabling CSRF.
#Bean
public SecurityWebFilterChain chain(ServerHttpSecurity http, AuthenticationWebFilter webFilter) {
return http.authorizeExchange().anyExchange().permitAll().and()
.csrf().disable()
.build();
}
Just put this code in #SpringBootApplication class, Like this and will work like charm
#SpringBootApplication
public class ConverterApplication {
public static void main(String[] args) {
SpringApplication.run(ConverterApplication.class, args);
}
#Bean
public SecurityWebFilterChain chain(ServerHttpSecurity http, AuthenticationWebFilter webFilter) {
return http.authorizeExchange().anyExchange().permitAll().and()
.csrf().disable()
.build();
}

spring security 4 custom login page

I would like to create custom pure html/js login page in Spring Security.
I use Spring Boot 1.2.5.RELEASE
I defined an application and configuration:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
#Configuration
#EnableWebSecurity
#EnableWebMvcSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("a").password("a").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable() // DISABLED CSRF protection to make it easier !
.authorizeRequests()
.antMatchers("/", "/login.html").permit
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login.html")
.permitAll()
.and()
.logout()
.permitAll()
.logoutUrl("/logout")
.logoutSuccessUrl("/");
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
My login page looks like that (copied from default page!)
<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
<h3>Login with Username and Password</h3><form name='f' action='/login' method='POST'>
<table>
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td> </tr>
</table>
</form></body></html>
But I still have: AUTHORIZATION_FAILURE
Is it possible to create pute html login page (without jsp, thymeleaf, etc.) ?
What do I do wrong in my code ?
You configured your login page to be at /login.html (using loginPage("/login.html")). This will also change the location to which you need to post the credentials to login. The documentation states:
If "/authenticate" was passed to this method [loginPage(String)] it update the defaults as
shown below:
/authenticate GET - the login form
/authenticate POST - process the credentials and if valid authenticate the user
/authenticate?error GET - redirect here for failed authentication attempts
/authenticate?logout GET - redirect here after successfully logging out
In order to make the login work, you need to make login.html post the credentials to /login.html instead of /login.

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

Resources