I want to implement one thing in my project, but it does not work. I have a jsp page with a list of students(allStudents.jsp), I want when the project starts so that the login page comes out and after such as the admin enters his login and password only when he could immediately go to the page where the list of students. But my project does not ask me to enter my login and password and immediately opens the page where the list of students is.
AuthorizationController.jsp
package adil.java.schoolmaven.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class AuthorizationController{
// If user will be successfully authenticated he/she will be taken to the login secure page.
#RequestMapping(value="/admin", method = RequestMethod.GET)
public ModelAndView adminPage() {
ModelAndView m = new ModelAndView();
m.addObject("title", "You have successfully logged in.");
m.addObject("message", "Home");
m.setViewName("admin");
return new ModelAndView("redirect: allStudents");
}
// Spring security will see this message.
#RequestMapping(value = "/login", method = RequestMethod.POST)
public ModelAndView login(#RequestParam(value = "error", required = false) String error,
#RequestParam(value = "logout", required = false) String logout) {
ModelAndView m = new ModelAndView();
if (error != null) {
m.addObject("error", "Invalid username and password");
}
if (logout != null) {
m.addObject("msg", "you successfully logged out");
}
m.setViewName("login");
return new ModelAndView("redirect: allStudents");
}
}
Student Controller
package adil.java.schoolmaven.controller;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletContext;
import adil.java.schoolmaven.entity.Student;
import adil.java.schoolmaven.service.StudentService;
import java.nio.file.FileSystemException;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class StudentController {
#Autowired
private ServletContext servletContext;
// Constructor based Dependency Injection
private StudentService studentService;
public StudentController() {
}
#Autowired
public StudentController(StudentService studentService) {
this.studentService = studentService;
}
#RequestMapping(value = "/allStudents", method = {RequestMethod.GET, RequestMethod.POST})
public ModelAndView displayAllUser() {
System.out.println("User Page Requested : All Students");
ModelAndView mv = new ModelAndView();
List<Student> studentList = studentService.getAllStudents();
mv.addObject("studentList", studentList);
mv.setViewName("allStudents");
return mv;
}
#RequestMapping(value = "/addStudent", method = RequestMethod.GET)
public ModelAndView displayNewUserForm() {
ModelAndView mv = new ModelAndView("addStudent");
mv.addObject("headerMessage", "Add Student Details");
mv.addObject("student", new Student());
return mv;
}
#PostMapping(value = "/addStudent")
public String saveNewStudent(#RequestParam("name") #NonNull String name,
#RequestParam("surname") #NonNull String surname,
#RequestParam("avatar") MultipartFile file)
throws IOException {
Student student = new Student();
student.setSurname(surname);
student.setName(name);
if (file != null && !file.isEmpty()) {
student.setAvatar(studentService.saveAvatarImage(file).getName());
}
studentService.saveStudent(student);
return "redirect:/allStudents";
}
#GetMapping(value = "/editStudent/{id}")
public ModelAndView displayEditUserForm(#PathVariable Long id) {
ModelAndView mv = new ModelAndView("editStudent");
Student student = studentService.getStudentById(id);
mv.addObject("headerMessage", "Редактирование студента");
mv.addObject("student", student);
return mv;
}
#PostMapping(value = "/editStudent")
public String saveEditedUser(
#RequestParam("id") Long id,
#RequestParam("name") String name,
#RequestParam("surname") String surname,
#RequestParam("avatar") MultipartFile file) {
try {
studentService.updateStudent(name, surname, file, studentService.getStudentById(id));
} catch (FileSystemException ex) {
ex.printStackTrace();
} catch (IOException e) {
return "redirect:/error";
}
return "redirect:/allStudents";
}
#GetMapping(value = "/deleteStudent/{id}")
public ModelAndView deleteUserById(#PathVariable Long id) {
studentService.deleteStudentById(id);
ModelAndView mv = new ModelAndView("redirect:/allStudents");
return mv;
}
}
mvc-dispacther-serlvet
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="adil.java.schoolmaven" />
<!-- Resolves Views Selected For Rendering by #Controllers to *.jsp Resources in the /WEB-INF/ Folder -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
login.jsp
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%# taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Custom login</title>
<style type="text/css">
.error {
color: #ff0000;
font-weight: bold;
}
.msg {
color: #008000;
font-weight: bold;
}
</style>
</head>
<body>
<h1 id="banner">Custom login form</h1>
<!-- invalid credentials error msg -->
<c:if test="${not empty error}">
<div class="error">${error}</div>
</c:if>
<!-- logged out msg -->
<c:if test="${not empty msg}">
<div class="msg">${msg}</div>
</c:if>
<!-- custom login form -->
<form name="loginform" action="<c:url value='/login'/>" method="POST">
<table>
<tr>
<td>Логин:</td> <!-- Enter username -->
<td><input type='text' name='username' value=''></td>
</tr>
<tr>
<td>Пароль:</td> <!-- Enter password -->
<td><input type='password' name='password' /></td>
</tr>
<tr>
<td colspan="2"> </td>
</tr>
<tr>
<td colspan='2'><input name="submit" type="submit" value="Submit" /></td>
</tr>
</table>
</form>
</body>
</html>
admin.jsp
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%# page language="java" session="true" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Secure page</title>
</head>
<body>
<h1>Title : ${title}</h1>
<h1>Message : ${message}</h1>
<!-- displaying the logged in user details. -->
<c:if test="${pageContext.request.userPrincipal.name != null}">
<span>Welcome: ${pageContext.request.userPrincipal.name}</span> | <span><a id="logout" href="${pageContext.servletContext.contextPath}/logout">Logout</a></span>
</c:if>
</body>
</html>
enter image description here
You need to configure Spring Security Config class that implements WebSecurityConfigurerAdapter. And configure your login page as a parameter. Please see my code for reference. And also go through this tutorial and try to implement it. It will give you good knowledge on how to setup things.
SecurityConfig.java
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
private final MyUserDetailsService userDetailsService;
private final CustomBasicAuthenticationEntryPoint customBasicAuthenticationEntryPoint;
#Autowired
public SecurityConfig(MyUserDetailsService userDetailsService, CustomBasicAuthenticationEntryPoint customBasicAuthenticationEntryPoint)
{
this.userDetailsService = userDetailsService;
this.customBasicAuthenticationEntryPoint = customBasicAuthenticationEntryPoint;
}
#Override
public void configure(AuthenticationManagerBuilder auth)
{
auth.authenticationProvider(getDaoAuthenticationProvider());
}
#Bean
public CustomDaoAuthenticationProvider getDaoAuthenticationProvider()
{
CustomDaoAuthenticationProvider daoAuthenticationProvider=new CustomDaoAuthenticationProvider();
daoAuthenticationProvider.setUserDetailsService(userDetailsService);
daoAuthenticationProvider.setPasswordEncoder(getBCryptPasswordEncoder());
return daoAuthenticationProvider;
}
/* BCrypt strength should 12 or more*/
#Bean
public PasswordEncoder getBCryptPasswordEncoder()
{
return new BCryptPasswordEncoder(12);
}
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.authorizeRequests()
.antMatchers("/anonymous*").anonymous()
.antMatchers("/register").permitAll()
.antMatchers("/users/**").hasAuthority(AuthorityConstants.ADMIN)
.antMatchers("/admin**").hasAuthority(AuthorityConstants.ADMIN)
.antMatchers("/profile/**").hasAuthority(AuthorityConstants.USER)
.antMatchers("/api/**").hasAnyAuthority(AuthorityConstants.API_USER,AuthorityConstants.ADMIN)
.antMatchers("/dba/**").hasAuthority(AuthorityConstants.DBA)
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.exceptionHandling()
.authenticationEntryPoint(customBasicAuthenticationEntryPoint)
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.successHandler(new CustomAuthenticationSuccessHandler(sessionHistoryRepository))
.failureHandler(new CustomAuthenticationFailureHandler(failedLoginRepository))
.permitAll()
.and()
.logout()
.deleteCookies("X-Auth-Token")
.clearAuthentication(true)
.invalidateHttpSession(true)
.logoutSuccessHandler(new CustomLogoutSuccessHandler())
.permitAll()
.and()
.exceptionHandling()
.accessDeniedHandler(new CustomAccessDeniedHandler(unauthorizedRequestRepository))
.and()
.rememberMe().rememberMeServices(springSessionRememberMeServices());
// Uses CorsConfigurationSource bean defined below
http.cors();
http.sessionManagement()
//.invalidSessionUrl("/login.html")
//.invalidSessionStrategy((request, response) -> request.logout())
.sessionFixation().migrateSession()
.maximumSessions(1)
.maxSessionsPreventsLogin(false)
.sessionRegistry(sessionRegistry());
http.csrf()
.disable();
http.authorizeRequests()
.antMatchers("/").permitAll()
.and()
.authorizeRequests().antMatchers("/console/**","/h2-console/**").permitAll();
http.headers()
.frameOptions().disable();
}
#Bean
public SpringSessionRememberMeServices springSessionRememberMeServices()
{
SpringSessionRememberMeServices rememberMeServices = new SpringSessionRememberMeServices();
rememberMeServices.setRememberMeParameterName("remember-me");
rememberMeServices.setValiditySeconds(ApplicationConstants.REMEMBERMETIMEOUT);
return rememberMeServices;
}
//Cors filter to accept incoming requests
#Bean
CorsConfigurationSource corsConfigurationSource()
{
CorsConfiguration configuration = new CorsConfiguration();
configuration.applyPermitDefaultValues();
configuration.setAllowedMethods(Collections.singletonList("*"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
#Override
public void configure(WebSecurity web) throws Exception
{
web
.ignoring()
.antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**","/h2-console/**","/console/**");
}
#Bean("authenticationManager")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception
{
return super.authenticationManagerBean();
}
#Bean
public SessionRegistry sessionRegistry()
{
return new SessionRegistryImpl();
}
}
Related
I'm new in spring.
I was trying to add a new goal to my database. Before I add spring security it's worked, but now if I click to add a new goal, I have a problem :
There was an unexpected error (type=Forbidden, status=403).
Forbidden
My goat-add.html :
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Goals</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
<header th:insert="blocks/header :: header"></header>
<div class="container mt-5 mb-5">
<h1>Your goals</h1>
<form action="/goal/add" method="post">
<input type="text" name="name" placeholder="Write your goal name" class="form-control"><br>
<textarea type="text" name="description" placeholder="Write your goal description" class="form-control"></textarea><br>
<button type="submit" class="btn btn-success">Add goal</button>
</form>
</div>
<div th:insert="blocks/footer :: footer"></div>
</body>
</html>
WebSecurityConfig class :
package com.evgzabozhan.GoatGoal.config;
import com.evgzabozhan.GoatGoal.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login","/registration").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService)
.passwordEncoder(NoOpPasswordEncoder.getInstance());
}
}
My controller :
package com.evgzabozhan.GoatGoal.controller;
import com.evgzabozhan.GoatGoal.model.Goal;
import com.evgzabozhan.GoatGoal.model.User;
import com.evgzabozhan.GoatGoal.repository.GoalRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.*;
#Controller
public class GoalController {
#Autowired
private GoalRepository goalRepository;
#GetMapping("/goal")
public String goal(Model model){
Iterable<Goal> goals = goalRepository.findAll();
model.addAttribute("goals",goals);
return "goal/goal-main";
}
#GetMapping("/goal/add")
public String getGoalAdd(Model model){
return "goal/goal-add";
}
#PostMapping("/goal/add")
public String postGoalAdd(#AuthenticationPrincipal User user,
#RequestParam String name,
#RequestParam String description, Model model){
Goal goal = new Goal(name,description,user);
goalRepository.save(goal);
model.addAttribute("message",user.getUsername());
return "redirect:/goal";
}
#GetMapping("/goal/{id}")
public String goalInfo(#PathVariable(value = "id") long id, Model model) {
if (!goalRepository.existsById(id)) {
return "redirect:/goal";
}
Optional<Goal> goal = goalRepository.findById(id);
ArrayList<Goal> result = new ArrayList<>();
goal.ifPresent(result::add);
model.addAttribute("goal", result);
return "goal/goal-info";
}
#GetMapping("/goal/{id}/edit")
public String goalEdit(#PathVariable(value = "id") long id, Model model){
if (!goalRepository.existsById(id)) {
return "redirect:/goal";
}
Optional<Goal> goal = goalRepository.findById(id);
ArrayList<Goal> result = new ArrayList<>();
goal.ifPresent(result::add);
model.addAttribute("goal", result);
return "goal/goal-edit";
}
#PostMapping("/goal/{id}/edit")
public String postGoalUpdate(#PathVariable(value = "id") long id,
#RequestParam String name,
#RequestParam String description,
Model model){
Goal goal = goalRepository.findById(id).orElseThrow();
goal.setName(name);
goal.setDescription(description);
goalRepository.save(goal);
return "redirect:/goal";
}
#PostMapping("/goal/{id}/remove")
public String postGoalRemove(#PathVariable(value = "id") long id, Model model){
Goal goal = goalRepository.findById(id).orElseThrow();
goalRepository.delete(goal);
return "redirect:/goal";
}
}
I read this problem can be if don't use csrf, but I don't understand how I can fix it.
All code there: https://github.com/evgzabozhan/GoatGoal
Thanks for your help!
I think this is because none of the goal calls is a permitted operation
.antMatchers("/login","/registration").permitAll()
should be
.antMatchers("/login","/registration","/goal").permitAll()
I add .csrf.disable() in configure method and it's work.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/login","/registration").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
it's working because crsf is enabled on default in Spring
There is a Spring MVC project. There are 3 classes Customer, Admin and Cook. They all work through links to the main User class. Accordingly, there are User tables, from which the rest work through the #OneToOne connection. I added Spring Security to the project. Also added html - authorization. When logging in, it gives me an error that I entered the data incorrectly, although everything is correct I enter from the database.
What's my mistake. What am I doing wrong?
User:
package com.tinychiefdelights.model;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import javax.persistence.*;
import javax.validation.constraints.Size;
import java.util.Collection;
import java.util.Collections;
#ApiModel
#Data
#Entity
#Table(name = "pg_user", schema = "public")
public class User implements UserDetails {
public User() { // Пустой конструктор для Hibernate
}
// Поля
private #Id
#GeneratedValue
Long id;
#Column(name = "login")
private String login;
#Size(min = 5, max = 30)
#Column(name = "password")
private String password;
#Enumerated(EnumType.STRING)
#Column(name = "role")
private Role role;
#Column(name = "name")
private String name;
#Column(name = "last_name")
private String lastName;
// Методы
//
// GrantedAuthority
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Collections.singletonList(new SimpleGrantedAuthority("ROLE_" + role));
}
// userName == login (одно и тоже)
#Override
public String getUsername() {
return login;
}
// Во всех флагах стоит TRUE, так как не используются
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
//
}
User:
public enum Role {
COOK, ADMIN, CUSTOMER
}
HOME:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org" xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Spring Security Example</title>
</head>
<body>
<h1>Welcome!</h1>
<p>Click <a th:href="#{/hello}">here</a> to see a greeting.</p>
</body>
</html>
Login:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Spring Security Example </title>
</head>
<body>
<div th:if="${param.error}">
Invalid username and password.
</div>
<div th:if="${param.logout}">
You have been logged out.
</div>
<form th:action="#{/login}" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
</body>
</html>
Hello:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Hello World!</title>
</head>
<body>
<h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1>
<form th:action="#{/logout}" method="post">
<input type="submit" value="Sign Out"/>
</form>
</body>
</html>
MvcConfig:
#Configuration
public class MvcConfig implements WebMvcConfigurer {
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/home").setViewName("home");
registry.addViewController("/").setViewName("home");
registry.addViewController("/hello").setViewName("hello");
registry.addViewController("/login").setViewName("login");
}
}
WebSecurityConfig:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// Поля
//
private UserService userService;
// Injects in SETTERS
//
#Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
// Methods
//
// Тут мы переопределяем метод конфигураций
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
// Тут мы переопределяем для работы с внешней БД
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
}
// Тут мы используем encoder для шифрования паролей
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// Возвращаем сервис пользовател для userDetServ
#Bean
public UserDetailsService userDetailsService() {
return userService;
}
}
You are storing passwords as plain text in DB and authentication is happening passwordEncoder comparison.
auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
Store password as BCryptPasswordEncoded when you are storing user in DB.
user.setPassword(passwordEncoder.encode(password));
OR
Compare plain text password (not recommended)
auth.userDetailsService(userDetailsService());
I'm making with using spring and hibernate. In my database i'm having several users with 3 different roles. I'm using BCryptPasswordEncoder, in database i'm having users with plain password, encoded password and {bcrypt}encoded password, i'm having problem becouse when i type users with plain passwords i can login, when i type password encoded or {bcrypt}encoded i can't login.
SecurityConfig.java
package com.spring.config;
import com.spring.service.UserDetails;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth ) throws Exception {
auth.authenticationProvider(authProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception{
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/managers/**").hasRole("MANAGER")
.antMatchers("/employees/**").hasRole("REGULAR_EMPLOYEE")
.antMatchers("/").permitAll()
.and().formLogin().loginPage("/").defaultSuccessUrl("/login").loginProcessingUrl("/loginAction").permitAll()
.and().logout().permitAll();
}
#Bean
public UserDetailsService userDetailsService(){
return new UserDetails();
}
#Autowired
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public DaoAuthenticationProvider authProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService());
authProvider.setPasswordEncoder(bCryptPasswordEncoder());
return authProvider;
}
}
UserDetails.java
package com.spring.service;
import com.spring.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class UserDetails implements UserDetailsService {
#Autowired
private UserService mUserService;
#Override
public org.springframework.security.core.userdetails.UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User user = mUserService.getUserByLogin(s);
org.springframework.security.core.userdetails.User.UserBuilder userBuilder;
userBuilder = org.springframework.security.core.userdetails.User.withUsername(user.getAccountLogin());
userBuilder.password(new BCryptPasswordEncoder().encode(user.getAccountPassword()));
userBuilder.roles(user.getRoleByRoleId().getRole());
return userBuilder.build();
}
}
plain-login.jsp
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%# page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Log in</title>
<meta charset="UTF-8">
<style>
.failed {
color: red;
}
.success {
color: green;
}
</style>
</head>
<body>
<form:form action="${pageContext.request.contextPath}/loginAction"
method="POST">
<c:if test="${param.error != null}">
<i class="failed">Wrong data!</i>
</c:if>
<c:if test="${param.logout != null}">
<i class="success">Logged out successfully!</i>
</c:if>
<p>
Login: <input type="text" name="username" />
</p>
<p>
Password: <input type="password" name="password" />
</p>
<input type="submit" value="Log in" />
</form:form>
</body>
</html>
I have only 2 page in my project "/register" and "/login". login.jsp page is coming from default spring security login. register.jsp is created by me.
My spring security configuration:
package com.cihangirmercan.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication().withUser("cihangir").password("mercan")
.roles("USER"); // the only user at the beginning
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login", "/register").permitAll() // anonym can login or register
.antMatchers("/").access("hasRole('USER')") // home page is not allowed if not user is logged in
.and().formLogin();
http.csrf().disable();
}
}
So, in the beginning, only one user id:"cihangir" and pass:"mercan" can pass the filter and login. What I want is after register with username and password, I want this new registration to has ROLE_USER and can login after that.
RegisterController:
package com.cihangirmercan.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
#Controller
#SessionAttributes("registerWarning")
public class RegisterController {
#RequestMapping(value = "/register", method = RequestMethod.GET)
public String showRegisterPage(ModelMap model) {
return "register";
}
#RequestMapping(value = "/register", method = RequestMethod.POST)
public String handleRegisterRequest(ModelMap model,
#RequestParam String username,
#RequestParam String password) {
// i want to give this username and password ROLE_USER
// hence user can login with spring security
// done
return "redirect:/login";
}
}
register.jsp:
<html>
<head>
<title>Register</title>
</head>
<body>
<h1>Register</h1>
<form action="/register" method="post" >
<label>Username:</label>
<input type="text" name="username" required><br><br>
<label>Password:</label>
<input type="password" name="password"><br><br>
<input type="submit" value="Register">
</form>
</body>
</html>
WelcomeController: (welcome page)
package com.cihangirmercan.controller;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
public class WelcomeController {
#RequestMapping(value = "/", method = RequestMethod.GET)
public String showWelcomePage(ModelMap model) {
model.put("username", getLoggedInUserName());
return "welcome";
}
private String getLoggedInUserName() {
Object principal = SecurityContextHolder.getContext()
.getAuthentication().getPrincipal();
if (principal instanceof UserDetails)
return ((UserDetails) principal).getUsername();
return principal.toString();
}
}
welcome.jsp:
<html>
<head>
<title>Home</title>
</head>
<body>
<h2>Home Page</h2>
<br>
<h4>${username} is at home.</h4>
</body>
</html>
Besides, web.xml and dispatcher-servlet and pom.xml they are all I have.
you have not configured your login correctly
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login", "/register").permitAll() // anonym can login or register
.antMatchers("/").access("hasRole('USER')") // home page is not allowed if not user is logged in
.and().formLogin().loginPage("/login")
.and()
.logout().logoutSuccessUrl("/register");
http.csrf().disable();
}
and you have configured the view resolver in your dispatch-xxx.xml, something like this
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
I solved my problem with using jdbc authentication.
It dynamically updates users and roles.
source: https://dzone.com/articles/spring-security-4-authenticate-and-authorize-users
I just started a project with uses Spring Security for authentication which uses Java configuration instead XML. That's my class SecurityConfig.java:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("kleber")
.password("123")
.roles("USER");
}
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/css/**", "/fonts/**", "/image/**", "/js/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/spring/index").permitAll()
.loginProcessingUrl("/spring/login").permitAll()
.usernameParameter("login")
.passwordParameter("senha")
.defaultSuccessUrl("/spring/home")
.failureUrl("/spring/erro-login")
.and()
.logout()
.logoutUrl("/spring/logout")
.logoutSuccessUrl("/spring/index").permitAll();
}
}
With this configuration, I can reach the login page, but after I inform my credencials (username and password) the system return to this same login page, despite the username and password informed are correct.
All this URLs informed in the class SecurityConfig are mapped in this controller:
#Controller
#RequestMapping(value="spring")
public class SpringController {
#RequestMapping(value="index")
public ModelAndView index() {
ModelAndView mav = new ModelAndView();
mav.setViewName("index");
return mav;
}
#RequestMapping(value="home")
public ModelAndView home() {
ModelAndView mav = new ModelAndView();
mav.setViewName("home");
return mav;
}
#RequestMapping(value="doLogin", method=RequestMethod.POST)
public void doLogin(HttpServletRequest request, HttpServletResponse response) {
//
}
#RequestMapping(value="logout")
public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException {
request.getSession().invalidate();
response.sendRedirect(request.getContextPath());
}
}
What I am doing wrong?
-->Still related to topic above:
I need implement this 'loginProcessingUrl', which is mapped in my controller this way:
#RequestMapping(value="doLogin", method=RequestMethod.POST)
public void doLogin(HttpServletRequest request, HttpServletResponse response) {
//
}
I already have in my application two classes which, according to the articles I read, will be necessary for this process, but I could be wrong and maybe i need another approach:
SampleAuthenticationManager
public class SampleAuthenticationManager implements AuthenticationManager {
static final List<GrantedAuthority> AUTHORITIES = new ArrayList<GrantedAuthority>();
static
{
AUTHORITIES.add(new SimpleGrantedAuthority("ROLE_USER"));
}
public Authentication authenticate(Authentication auth) throws AuthenticationException
{
if (auth.getName().equals(auth.getCredentials()))
{
return new UsernamePasswordAuthenticationToken(auth.getName(), auth.getCredentials(), AUTHORITIES);
}
throw new BadCredentialsException("Bad Credentials");
}
}
DefaultAuthenticationProcessingFilter
public class DefaultAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
private static final String INTERCEPTOR_PROCESS_URL = "/spring/doLogin";
private static AuthenticationManager am = new SampleAuthenticationManager();
protected DefaultAuthenticationProcessingFilter() {
super(INTERCEPTOR_PROCESS_URL);
// TODO Auto-generated constructor stub
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
// TODO Auto-generated method stub
String login = request.getParameter("login");
String senha = request.getParameter("senha");
Authentication input = new UsernamePasswordAuthenticationToken(login, senha);
Authentication output = null;
try {
output = am.authenticate(input);
SecurityContextHolder.getContext().setAuthentication(output);
getSuccessHandler().onAuthenticationSuccess(request, response, output);
} catch (AuthenticationException failed) {
getFailureHandler().onAuthenticationFailure(request, response, failed);
}
return output;
}
}
In this scenario, how I should implement the method doLogin from my controller? Take in consideration that in this moment I am using inMemory authentication, for later extend my project for use a database.
Ok, I managed to solve my problem; it happens I make some mess with the Url informed in the SecurityConfig and the Url's in my views. I need remember in the future: in the class, use always //. In the view, always use .
In my case, the views was written this way:
index.jsp -> the login page
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%# page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<c:url value="/spring/login" var="loginUrl"/>
<form method="post" action="${loginUrl}">
usuário: <input type="text" name="login" size=20> <br/>
senha: <input type="password" name="senha" size=20> <br/>
<input type="submit" value="entrar"> <br/>
</form>
</body>
</html>
home.jsp -> the "destiny" page (dashboard): only for test purposes in this state of project
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%# page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>
<c:out value="${pageContext.request.remoteUser}"/>
Logout
</h2>
</body>
</html>
Final code for the class SecurityConfig.java
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("kleber")
.password("123")
.roles("USER");
}
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/css/**", "/fonts/**", "/image/**", "/js/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/spring/index").permitAll()
.loginProcessingUrl("/spring/login").permitAll()
.usernameParameter("login")
.passwordParameter("senha")
.successHandler(new CustomAuthenticationSuccessHandler())
.failureHandler(new CustomAuthenticationFailureHandler())
.and()
.logout()
.logoutUrl("/spring/logout")
.logoutSuccessUrl("/spring/index").permitAll();
}
}