While log in with spring-security on wildfly i get this error-page:
{"timestamp":1464679377206,"status":999,"error":"None","message":"No message available"}
after refresh it redirects me on my custom error page. Then if I clear error-link (like that http://myapp/error -> http://myapp) application works correctly. When I launch this app with spring-boot (not wildfly) there is no such problem.
Application class
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(applicationClass);
}
private static Class<Application> applicationClass = Application.class;
}
Thymeleaf login form
<div sec:authorize="isAnonymous()" id="anonymous-navbar" class="navbar-collapse collapse">
<form th:action="#{/login}" method="post" class="navbar-form navbar-right">
<div class="form-group">
<input type="text" name="username" placeholder="User" class="form-control" />
</div>
<div class="form-group">
<input type="password" name="password" placeholder="Password" class="form-control" />
</div>
<button type="submit" class="btn btn-success" value="login">Log in</button>
</form>
Security configuration
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserService userService;
#Autowired
#Qualifier("userServiceImpl")
UserDetailsService userDetailsService;
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home", "/signup", "/add_person").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/images/**");
}
}
After debugging spring class DefaultErrorAttributes, which sends the message I got this error
FirewalledRequest[ HttpServletRequestImpl [ GET /PersonalFinance/error ]]
I've watched wildfly logs and haven't found anything useful.
There are some same questions:
Spring Security with basic auth redirecting to /error for invalid credentials
Spring Security - Remember Me Authentication Error
But these answers haven't solved the problem
Error occurred cause folder with images was not included to project, but was specified in spring-security configuration. Thus spring didn't find this path and threw an error.
Related
I know that there is many questions like this, but nothing I found helped me fix the issue.
I'm using Spring Boot with security to handle login, with custom login page. This is my config:
#SpringBootApplication
public class CompetencyMatrixApplication {
public static void main(String[] args) {
SpringApplication.run(CompetencyMatrixApplication.class, args);
}
}
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
private final UserDetailsService userDetailsService;
public SecurityConfig(UserDetailsService userDetailsService)
{
this.userDetailsService = userDetailsService;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/matrix", "/matrix/show", "/cas/getImage", "/documentModal").access("hasRole('2')")
.antMatchers("/matrix/fromFile", "/matrix/upload").access("hasRole('1')")
.antMatchers("/cas/new", "/cas/uploadImage").access("hasRole('1')")
.antMatchers("/department/**", "/departmentType/**").access("hasRole('1')")
.antMatchers("/employee/**").access("hasRole('1')")
.antMatchers("/position", "/position/**").access("hasRole('1')")
.antMatchers("/login").permitAll()
.antMatchers("/resources/**").permitAll()
.and().formLogin()
.loginPage("/sign-in").permitAll()
.defaultSuccessUrl("/",true)
.failureUrl("/sign-in?error")
.usernameParameter("email")
.passwordParameter("password")
.and().logout().logoutSuccessUrl("/sign-in?logout")
.and().exceptionHandling().accessDeniedPage("/403");
}
}
and login page (just the form part)
<c:url var="loginUrl" value="/login"/>
<form action="${loginUrl}" method="post">
<div class="mb-4">
<label for="email" class="block text-gray-700 text-sm font-bold mb-2">Email</label>
<input id="email" type='text' name='email' value=''
class="block appearance-none w-full bg-gray-200 border border-gray-200 text-gray-700 py-3 px-4 pr-8 rounded leading-tight focus:outline-none focus:bg-white focus:border-gray-500">
</div>
<div class="mb-4">
<label for="password" class="block text-gray-700 text-sm font-bold mb-2">Hasło</label>
<input id="password" type='password' name='password'
class="block appearance-none w-full bg-gray-200 border border-gray-200 text-gray-700 py-3 px-4 pr-8 rounded leading-tight focus:outline-none focus:bg-white focus:border-gray-500">
</div>
<input name="submit" type="submit" value="Zaloguj"
class="shadow bg-purple-500 hover:bg-purple-400 focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded"/>
</form>
So I get my custom page for login, but when I submit it I get 404 Whitelabel Error Page.
What am I missing here? Every example I saw was just using the default /login url to post login details and it worked, mine obviously doesn't even reach UserDetailsService
Found the issue, if someone comes here looking for solution, for me adding
http.csrf().disable(); did the trick
I'm learning Spring Security at creating simple login form. I'm using java configuration. I've in-memory users and a simple filter chain.
But when I input an existing username and password combination Spring redirect me back to login form with url: login?error.
This is my Spring Security configuration class:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// #Autowired
// AuthProvider provider;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user1").password("").roles("USER")
.and()
.withUser("user2").password("").roles("USER")
.and()
.withUser("admin").password("1").roles("ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll();
}
// #Override
// protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// auth.authenticationProvider(provider);
// }
}
This is my JSP form:
<%# page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
${message}
<br>
<form method="post" action="/login">
<input type="text" name="login"/>
<input type="text" name="pass"/>
<input type="submit" value="enter"/>
</form>
</body>
</html>
in your code
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user1").password("").roles("USER")
.and()
.withUser("user2").password("").roles("USER")
.and()
.withUser("admin").password("1").roles("ADMIN");
}
replace the #Autowired with #Override
and follow this practice here [1]: https://www.baeldung.com/spring-security-login
... auth.inMemoryAuthentication()
.withUser("user1").password(passwordEncoder().encode("user1Pass")).roles("USER")
.and() ...
using BCryptPasswordEncoder as follows as a bean in same code
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
Take a look at formLogin(String loginPage) javadoc - default parameters for username and password are username and password. So you should reference them like that in your .jsp and then the login should work. So you should try refactoring jsp to following:
<%# page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
${message}
<br>
<form method="post" action="/login">
<input type="text" id="username" name="username"/>
<input type="password" id="password" name="password"/>
<input type="submit" value="enter"/>
</form>
</body>
</html>
For admin user, try with:
.withUser("admin").password("{noop}1").roles("ADMIN");
This is a way to store passwords in a plain text (obviously a not recommended way...). By adding {noop} prefix, you indicate you want to use NoopPasswordEncoder.
Otherwise, you should specify password encoder, for example:
#Bean
public BCryptPasswordEncoder passEncoder() {
return new BCryptPasswordEncoder();
}
and update your SecurityConfig like:
#Autowired
private BCryptPasswordEncoder passEncoder;
#Override
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.passwordEncoder(passEncoder)
.withUser("user1").password("").roles("USER")
.and()
.withUser("user2").password("").roles("USER")
.and()
.withUser("admin").password("1").roles("ADMIN");
}
I had all three error in my code, described above. I acceped all three solutions and it works for me. Thank you!
Worked code:
My SecurityConfig:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user1").password(passwordEncoder().encode("1")).roles("USER")
.and()
.withUser("user2").password(passwordEncoder().encode("1")).roles("USER")
.and()
.withUser("admin").password(passwordEncoder().encode("1")).roles("ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.usernameParameter("login")
.passwordParameter("pass")
.permitAll();
}
}
My jsp form:
<%# page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
${message}
<br>
<form method="post" action="/login">
<input type="text" name="login"/>
<input type="text" name="pass"/>
<input type="submit" value="enter"/>
</form>
</body>
</html>
I'm trying to configure spring secutiry in my SpringBoot 2 application.
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/registration").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll()
.defaultSuccessUrl("/users")
.and()
.logout().permitAll();
}
#Override
public UserDetailsService userDetailsService() {
UserDetails user =
User.withDefaultPasswordEncoder()
.username("u")
.password("p")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
#Configuration
public class MvcConfig implements WebMvcConfigurer {
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
}
}
login.mustache
<form method="post" action="/login">
<input type="text" name="username" id="username" placeholder="Login" /><br>
<input type="password" name="password" id="password" placeholder="Password" /><br>
<input type="hidden" name="_csrf" value="{{_csrf.token}}">
<button type="submit">Login</button>
</form>
I expect to be redirected to /users page. But actually I get error code = 302 and I appear at /login/error
SOLUTION: I've added #Bean annotation to userDetailsService() and it helped.
You have to expose your UserDetailsService as a bean, see Spring Boot Reference:
84.2 Change the AuthenticationManager and Add User Accounts
If you provide a #Bean of type AuthenticationManager, AuthenticationProvider, or UserDetailsService, the default #Bean for InMemoryUserDetailsManager is not created, so you have the full feature set of Spring Security available (such as various authentication options).
The easiest way to add user accounts is to provide your own UserDetailsService bean.
Your modified code:
#Bean
#Override
public UserDetailsService userDetailsService() {
UserDetails user =
User.withDefaultPasswordEncoder()
.username("u")
.password("p")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
I have a Spring Boot application which is able to login and register new users. My users are saved in a database (so far, I use in-memory H2 databse for testing).
The service is secured with OAuth2 (it is an auth server for other services I am developing).
Everything works fine and I am able to check the user's credentials but I would like to redirect the user somewhere after successful login. It works if I access the login page with the response_type=token parameter.
http://localhost:9000/auth/oauth/authorize?response_type=token&client_id=client&redirect_uri=http://localhost:9000/auth/user
But when I access the login page directly and login, it redirects me to the page I selected as my default success page but without the token or anything else that would indicate that the user is logged in and I get 401. Going straight to the /login and using the correct credentials results in this:
<oauth>
<error_description>
Full authentication is required to access this resource
</error_description>
<error>unauthorized</error>
</oauth>
Could someone point out to me what I need to adjust to make the login work?
WebSecurityConfig:
#Configuration
#Order(-20)
#EnableResourceServer
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("userDetailsService")
private UserDetailsService userDetailsService;
#Autowired
private AuthenticationManager authenticationManager;
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.authorizeRequests()
.antMatchers("/register", "/confirm").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/")
.permitAll()
.and()
.requestMatchers()
.antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access", "/register", "/confirm")
.and()
.logout()
.permitAll();
// #formatter:on
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.parentAuthenticationManager(authenticationManager);
auth.userDetailsService(userDetailsService);
}
}
OAuth2Config:
#Configuration
#EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
#Autowired
#Qualifier("userDetailsService")
private UserDetailsService userDetailsService;
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private TokenStore tokenStore;
#Autowired
private DataSource dataSource;
// password encryptor
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer configurer) throws Exception {
configurer.authenticationManager(authenticationManager);
configurer.userDetailsService(userDetailsService);
configurer.tokenStore(tokenStore);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
}
}
LoginController:
#Controller
public class LoginController {
#GetMapping("/login")
public String login() {
return "login";
}
}
Login page:
<body>
<div class="container">
<form class="form-signin" th:action="#{/login}" method="post">
<h2 class="form-signin-heading">Sign in</h2>
<div th:if="${param.error}">Invalid username and password.</div>
<div th:if="${param.logout}">You have been logged out.</div>
<label for="inputEmail" class="sr-only">Email</label>
<input type="text" id="username"
class="form-control" placeholder="Email" name="username" th:required="required" th:autofocus="autofocus" />
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" id="inputPassword"
class="form-control" placeholder="Password" name="password" th:required="required" />
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
</div>
<!-- /container -->
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
Thank you for any help. I am happy to provide more details if this is not enough.
EDIT: What I want is basically a steteless authentication between the Auth server and other microservices but sessions-based login on the Auth server itself.
Check this first:
Spring Security OAuth 2 with form login
Provided that an access token is being created with basic form login, I would add custom authentication success handler:
WebSecurityConfig:
#Autowired
private AuthenticationSuccessHandler myAuthenticationSuccessHandler;
//
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/")
.successHandler(myAuthenticationSuccessHandler)
And the handler "MySimpleUrlAuthenticationSuccessHandler":
#Component("myAuthenticationSuccessHandler")
public class MySimpleUrlAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
//logic to grant access
}
Every tutorial I see with Spring MVC and AngularJs uses Spring Boot configuration. I am not using Spring Boot so I'm wondering if there are any pointers anybody has on how to handle AngularJS login submission server side WITHOUT using Spring Boot.
So my form is the same basic one from the Spring Security demo here
<div class="alert alert-danger" ng-show="error">
There was a problem logging in. Please try again.
</div>
<form role="form" ng-submit="login()">
<div class="form-group">
<label for="username">Username:</label> <input type="text"
class="form-control" id="username" name="username" ng-model="credentials.username"/>
</div>
<div class="form-group">
<label for="password">Password:</label> <input type="password"
class="form-control" id="password" name="password" ng-model="credentials.password"/>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
The function to authenticate on login() is as follows:
//the authentication function
var authenticate = function(credentials, callback){
var headers =
credentials ?
{
authorization : "Basic " + btoa(credentials.username + ":" + credentials.password)
}
: {};
$http.get('user', {headers : headers}).success(function(data){
if(data.userName){
$rootScope.authenticated = true;
} else {
$rootScope.authenticated = false;
}
callback && callback();
}).error(function(){
$rootScope.authenticated = false;
callback && callback();
});
};
So now the next part is to configure Spring to handle the username and password properties of the credentials object. On the server side, I have a basic WebSecurityConfigurerAdapter:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
DataSource dataSource;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/profile").authenticated()
.anyRequest().permitAll()
.and()
.formLogin()
.loginPage("/signin")
.and()
.logout()
.permitAll();
//.and()
//.requiresChannel()
// .antMatchers("/register").requiresSecure();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
}
}
I know I have to configure a java.security.Principal in there somehow, but like I said, anything I've found has been for spring boot.