BAEL-509 (#2114)
* BAEL-509: Initial Commit - working but needs a few fixes to REST API, etc. * Fixed Authentication Failure - added subscription handlers - sufficient for Websocket Authentication/Authorization - still some issues to resolve with subscriptions and REST API * Final version * CSRF token controller - cleanup of chat wrapper
This commit is contained in:
committed by
KevinGilmore
parent
70ae331cd7
commit
db2bb252de
+56
@@ -0,0 +1,56 @@
|
||||
package com.baeldung.springsecuredsockets.config;
|
||||
|
||||
import org.h2.tools.Server;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
import org.springframework.web.servlet.resource.PathResourceResolver;
|
||||
import org.springframework.web.servlet.view.JstlView;
|
||||
import org.springframework.web.servlet.view.UrlBasedViewResolver;
|
||||
import java.sql.SQLException;
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
@EnableJpaRepositories
|
||||
@ComponentScan("com.baeldung.springsecuredsockets")
|
||||
@Import({ SecurityConfig.class, DataStoreConfig.class, SocketBrokerConfig.class, SocketSecurityConfig.class })
|
||||
public class AppConfig extends WebMvcConfigurerAdapter {
|
||||
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
registry.addViewController("/").setViewName("index");
|
||||
registry.addViewController("/login").setViewName("login");
|
||||
registry.addViewController("/secured/socket").setViewName("socket");
|
||||
registry.addViewController("/secured/success").setViewName("success");
|
||||
registry.addViewController("/denied").setViewName("denied");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UrlBasedViewResolver viewResolver() {
|
||||
final UrlBasedViewResolver bean = new UrlBasedViewResolver();
|
||||
bean.setPrefix("/WEB-INF/jsp/");
|
||||
bean.setSuffix(".jsp");
|
||||
bean.setViewClass(JstlView.class);
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
registry.addResourceHandler("/resources/**")
|
||||
.addResourceLocations("/", "/resources/")
|
||||
.setCachePeriod(3600)
|
||||
.resourceChain(true)
|
||||
.addResolver(new PathResourceResolver());
|
||||
}
|
||||
|
||||
// View H2
|
||||
@Bean(initMethod="start", destroyMethod="stop")
|
||||
public Server h2Console () throws SQLException {
|
||||
return Server.createWebServer("-web","-webAllowOthers","-webDaemon","-webPort", "8082");
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package com.baeldung.springsecuredsockets.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.JpaVendorAdapter;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.orm.jpa.vendor.Database;
|
||||
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Properties;
|
||||
|
||||
@Configuration
|
||||
@ComponentScan("com.baeldung.springsecuredsockets")
|
||||
@EnableTransactionManagement
|
||||
@EnableJpaRepositories("com.baeldung.springsecuredsockets.repositories")
|
||||
public class DataStoreConfig {
|
||||
|
||||
//Configuration for embededded data store through H2
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
return new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.setName("socketDB")
|
||||
.addScript("classpath:schema.sql")
|
||||
.addScript("classpath:data.sql")
|
||||
.setScriptEncoding("UTF-8")
|
||||
.continueOnError(true)
|
||||
.ignoreFailedDrops(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JpaVendorAdapter jpaVendorAdapter() {
|
||||
final HibernateJpaVendorAdapter bean = new HibernateJpaVendorAdapter();
|
||||
bean.setDatabase(Database.H2);
|
||||
bean.setGenerateDdl(true);
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
|
||||
final LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean();
|
||||
bean.setDataSource(dataSource);
|
||||
bean.setJpaVendorAdapter(jpaVendorAdapter());
|
||||
bean.setPackagesToScan("com.baeldung.springsecuredsockets");
|
||||
|
||||
//Set properties on Hibernate
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
|
||||
properties.setProperty("hibernate.hbm2ddl.auto", "update");
|
||||
bean.setJpaProperties(properties);
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JpaTransactionManager transactionManager(EntityManagerFactory emf) {
|
||||
return new JpaTransactionManager(emf);
|
||||
}
|
||||
|
||||
}
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
package com.baeldung.springsecuredsockets.config;
|
||||
|
||||
import com.baeldung.springsecuredsockets.security.CustomAccessDeniedHandler;
|
||||
import com.baeldung.springsecuredsockets.security.CustomDaoAuthenticationProvider;
|
||||
import com.baeldung.springsecuredsockets.security.CustomLoginSuccessHandler;
|
||||
import com.baeldung.springsecuredsockets.security.CustomLogoutSuccessHandler;
|
||||
import com.baeldung.springsecuredsockets.security.CustomUserDetailsService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
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.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
||||
|
||||
/**
|
||||
* @EnableGlobalAuthentication annotates:
|
||||
* @EnableWebSecurity
|
||||
* @EnableWebMvcSecurity
|
||||
* @EnableGlobalMethodSecurity Passing in 'prePostEnabled = true' allows:
|
||||
* <p>
|
||||
* Pre/Post annotations such as:
|
||||
* @PreAuthorize("hasRole('ROLE_USER')")
|
||||
*/
|
||||
|
||||
@Configuration
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
|
||||
@EnableWebSecurity
|
||||
@ComponentScan("com.baeldung.springsecuredsockets")
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
private CustomUserDetailsService customUserDetailsService;
|
||||
|
||||
/**
|
||||
* Login, Logout, Success, and Access Denied beans/handlers
|
||||
*/
|
||||
|
||||
@Bean
|
||||
public AccessDeniedHandler accessDeniedHandler() {
|
||||
return new CustomAccessDeniedHandler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LogoutSuccessHandler logoutSuccessHandler() {
|
||||
return new CustomLogoutSuccessHandler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationSuccessHandler loginSuccessHandler() {
|
||||
return new CustomLoginSuccessHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Authentication beans
|
||||
*/
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder encoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DaoAuthenticationProvider authenticationProvider() {
|
||||
final DaoAuthenticationProvider bean = new CustomDaoAuthenticationProvider();
|
||||
bean.setUserDetailsService(customUserDetailsService);
|
||||
bean.setPasswordEncoder(encoder());
|
||||
return bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Order of precedence is very important.
|
||||
* <p>
|
||||
* Matching occurs from top to bottom - so, the topmost match succeeds first.
|
||||
*/
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.antMatchers("/", "/index", "/authenticate")
|
||||
.permitAll()
|
||||
.antMatchers("/secured/**/**",
|
||||
"/secured/success", "/secured/socket", "/secured/success")
|
||||
.authenticated()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin()
|
||||
.loginPage("/login").permitAll()
|
||||
.usernameParameter("username")
|
||||
.passwordParameter("password")
|
||||
.loginProcessingUrl("/authenticate")
|
||||
.successHandler(loginSuccessHandler())
|
||||
.failureUrl("/denied").permitAll()
|
||||
.and()
|
||||
.logout()
|
||||
.logoutSuccessHandler(logoutSuccessHandler())
|
||||
.and()
|
||||
/**
|
||||
* Applies to User Roles - not to login failures or unauthenticated access attempts.
|
||||
*/
|
||||
.exceptionHandling()
|
||||
.accessDeniedHandler(accessDeniedHandler())
|
||||
.and()
|
||||
.authenticationProvider(authenticationProvider());
|
||||
|
||||
/** Disabled for local testing */
|
||||
http
|
||||
.csrf().disable();
|
||||
|
||||
/** This is solely required to support H2 console viewing in Spring MVC with Spring Security */
|
||||
http
|
||||
.headers()
|
||||
.frameOptions()
|
||||
.disable();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.authenticationProvider(authenticationProvider());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web.ignoring().antMatchers("/resources/**");
|
||||
}
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.baeldung.springsecuredsockets.config;
|
||||
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
|
||||
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
|
||||
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableWebSocketMessageBroker
|
||||
@ComponentScan("com.baeldung.springsecuredsockets.controllers")
|
||||
public class SocketBrokerConfig extends AbstractWebSocketMessageBrokerConfigurer {
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerRegistry config) {
|
||||
config.enableSimpleBroker("/secured/history");
|
||||
config.setApplicationDestinationPrefixes("/spring-security-mvc-socket");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
registry.addEndpoint("/secured/chat").withSockJS();
|
||||
}
|
||||
}
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.baeldung.springsecuredsockets.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry;
|
||||
import org.springframework.security.config.annotation.web.socket.AbstractSecurityWebSocketMessageBrokerConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class SocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
|
||||
|
||||
@Override
|
||||
protected boolean sameOriginDisabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
|
||||
messages
|
||||
.simpDestMatchers("/secured/**").authenticated()
|
||||
.anyMessage().authenticated();
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.baeldung.springsecuredsockets.config;
|
||||
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.springframework.web.WebApplicationInitializer;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRegistration;
|
||||
|
||||
public class WebAppInitializer implements WebApplicationInitializer {
|
||||
|
||||
@Override
|
||||
public void onStartup(ServletContext container) throws ServletException {
|
||||
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
|
||||
context.register(AppConfig.class);
|
||||
context.setServletContext(container);
|
||||
|
||||
ServletRegistration.Dynamic servlet = container.addServlet("dispatcher", new DispatcherServlet(context));
|
||||
servlet.setLoadOnStartup(1);
|
||||
servlet.addMapping("/");
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.baeldung.springsecuredsockets.controllers;
|
||||
|
||||
import org.springframework.security.web.csrf.CsrfToken;
|
||||
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.ResponseBody;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@Controller
|
||||
public class CsrfTokenController {
|
||||
@RequestMapping(value = "/csrf", method = RequestMethod.GET)
|
||||
public @ResponseBody
|
||||
String getCsrfToken(HttpServletRequest request) {
|
||||
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
|
||||
return csrf.getToken();
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.baeldung.springsecuredsockets.controllers;
|
||||
|
||||
import com.baeldung.springsecuredsockets.transfer.socket.Message;
|
||||
import com.baeldung.springsecuredsockets.transfer.socket.OutputMessage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||
import org.springframework.messaging.handler.annotation.SendTo;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
@Controller
|
||||
public class SocketController {
|
||||
|
||||
@Autowired
|
||||
private SimpMessagingTemplate simpMessagingTemplate;
|
||||
private static final Logger log = LoggerFactory.getLogger(SocketController.class);
|
||||
|
||||
@MessageMapping("/secured/chat")
|
||||
@SendTo("/secured/history")
|
||||
public OutputMessage send(Message msg) throws Exception {
|
||||
OutputMessage out = new OutputMessage(msg.getFrom(), msg.getText(), new SimpleDateFormat("HH:mm").format(new Date()));
|
||||
return out;
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package com.baeldung.springsecuredsockets.domain;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.Set;
|
||||
|
||||
@Entity
|
||||
@Table(name = "role")
|
||||
public class Role {
|
||||
|
||||
@Id
|
||||
//Slight increase in performance over GenerationType.IDENTITY
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
@Column(name = "role_id", updatable = false, nullable = false)
|
||||
private long role_id;
|
||||
|
||||
@Column(name = "role", nullable = false)
|
||||
private String role;
|
||||
|
||||
/**
|
||||
* Many to Many Example - see Role.
|
||||
* <p>
|
||||
* One User many have many Roles.
|
||||
* Each Role may be assigned to many Users.
|
||||
*/
|
||||
@ManyToMany(mappedBy = "roles", fetch = FetchType.EAGER)
|
||||
private Set<User> users;
|
||||
|
||||
public long getRole_id() {
|
||||
return role_id;
|
||||
}
|
||||
|
||||
public void setRole_id(long role_id) {
|
||||
this.role_id = role_id;
|
||||
}
|
||||
|
||||
public String getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
public void setRole(String role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
public Set<User> getUsers() {
|
||||
return users;
|
||||
}
|
||||
|
||||
public void setUsers(Set<User> users) {
|
||||
this.users = users;
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package com.baeldung.springsecuredsockets.domain;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.Set;
|
||||
|
||||
//Custom User Model
|
||||
|
||||
@Entity
|
||||
@Table(name = "user")
|
||||
public class User {
|
||||
|
||||
@Id
|
||||
//Slight increase in performance over GenerationType.IDENTITY
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
@Column(name = "user_id", updatable = false, nullable = false)
|
||||
private long user_id;
|
||||
|
||||
@Column(name = "username", nullable = false)
|
||||
private String username;
|
||||
|
||||
@Column(name = "password", nullable = false)
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* Many to Many Example - see Role.
|
||||
* <p>
|
||||
* One User many have many Roles.
|
||||
* Each Role may be assigned to many Users.
|
||||
*/
|
||||
@ManyToMany(fetch = FetchType.EAGER)
|
||||
@JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
|
||||
private Set<Role> roles;
|
||||
|
||||
public long getUser_id() {
|
||||
return user_id;
|
||||
}
|
||||
|
||||
public void setUser_id(long user_id) {
|
||||
this.user_id = user_id;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public Set<Role> getRoles() {
|
||||
return roles;
|
||||
}
|
||||
|
||||
public void setRoles(Set<Role> roles) {
|
||||
this.roles = roles;
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.baeldung.springsecuredsockets.repositories;
|
||||
|
||||
|
||||
import com.baeldung.springsecuredsockets.domain.User;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface UserRepository extends JpaRepository<User, Long> {
|
||||
User findByUsername(String username);
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.baeldung.springsecuredsockets.security;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Applies to User Roles - not to login failures or unauthenticaed access attempts.
|
||||
*/
|
||||
|
||||
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
|
||||
|
||||
@Override
|
||||
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exc) throws IOException, ServletException {
|
||||
response.setStatus(HttpStatus.BAD_REQUEST.value());
|
||||
response.sendRedirect(request.getContextPath() + "/denied");
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.baeldung.springsecuredsockets.security;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
|
||||
public class CustomDaoAuthenticationProvider extends DaoAuthenticationProvider {
|
||||
|
||||
Logger log = LoggerFactory.getLogger(CustomDaoAuthenticationProvider.class);
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
|
||||
String name = authentication.getName();
|
||||
String password = authentication.getCredentials().toString();
|
||||
UserDetails u = null;
|
||||
|
||||
try {
|
||||
u = getUserDetailsService().loadUserByUsername(name);
|
||||
} catch (UsernameNotFoundException ex) {
|
||||
log.error("User '" + name + "' not found");
|
||||
} catch (Exception e) {
|
||||
log.error("Exception in CustomDaoAuthenticationProvider: " + e);
|
||||
}
|
||||
|
||||
if (u != null) {
|
||||
if (u.getPassword().equals(password)) {
|
||||
return new UsernamePasswordAuthenticationToken(u, password, u.getAuthorities());
|
||||
}
|
||||
}
|
||||
|
||||
throw new BadCredentialsException(messages.getMessage("CustomDaoAuthenticationProvider.badCredentials", "Bad credentials"));
|
||||
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.baeldung.springsecuredsockets.security;
|
||||
|
||||
import com.baeldung.springsecuredsockets.domain.User;
|
||||
import com.baeldung.springsecuredsockets.repositories.UserRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
public class CustomLoginSuccessHandler implements AuthenticationSuccessHandler {
|
||||
|
||||
@Autowired
|
||||
UserRepository userRepository;
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
|
||||
User user = userRepository.findByUsername(authentication.getName());
|
||||
response.setStatus(HttpStatus.OK.value());
|
||||
response.sendRedirect(request.getContextPath() + "/secured/success");
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.baeldung.springsecuredsockets.security;
|
||||
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
public class CustomLogoutSuccessHandler implements LogoutSuccessHandler {
|
||||
@Override
|
||||
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
||||
throws IOException, ServletException {
|
||||
|
||||
response.setStatus(HttpStatus.OK.value());
|
||||
response.sendRedirect(request.getContextPath() + "/index");
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package com.baeldung.springsecuredsockets.security;
|
||||
|
||||
import com.baeldung.springsecuredsockets.domain.Role;
|
||||
import com.baeldung.springsecuredsockets.domain.User;
|
||||
import com.baeldung.springsecuredsockets.repositories.UserRepository;
|
||||
import com.baeldung.springsecuredsockets.transfer.user.CustomUserDetails;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
@Service()
|
||||
public class CustomUserDetailsService implements UserDetailsService {
|
||||
|
||||
Logger log = LoggerFactory.getLogger(CustomUserDetailsService.class);
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
public CustomUserDetailsService() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
try {
|
||||
User user = userRepository.findByUsername(username);
|
||||
if (user != null) return new CustomUserDetails(user, getAuthorities(user));
|
||||
} catch (Exception ex) {
|
||||
log.error("Exception in CustomUserDetailsService: " + ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Collection<GrantedAuthority> getAuthorities(User user) {
|
||||
Collection<GrantedAuthority> authorities = new HashSet<>();
|
||||
for (Role role : user.getRoles()) {
|
||||
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getRole());
|
||||
authorities.add(grantedAuthority);
|
||||
}
|
||||
return authorities;
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.baeldung.springsecuredsockets.security;
|
||||
|
||||
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
|
||||
|
||||
/**
|
||||
* This is required to enable springSecurityFilterChain.
|
||||
*
|
||||
* Remember that Spring Security utilizes filters to intercept and manage requests
|
||||
* according to the specified authorization and authentication rules
|
||||
*/
|
||||
|
||||
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.baeldung.springsecuredsockets.transfer.socket;
|
||||
|
||||
public class Message {
|
||||
|
||||
private String from;
|
||||
private String text;
|
||||
|
||||
public String getFrom() {
|
||||
return from;
|
||||
}
|
||||
public void setFrom(String from) {
|
||||
this.from = from;
|
||||
}
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.baeldung.springsecuredsockets.transfer.socket;
|
||||
|
||||
public class OutputMessage extends Message {
|
||||
|
||||
private String time;
|
||||
|
||||
public OutputMessage(final String from, final String text, final String time) {
|
||||
setFrom(from);
|
||||
setText(text);
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public String getTime() {
|
||||
return time;
|
||||
}
|
||||
public void setTime(String time) { this.time = time; }
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.baeldung.springsecuredsockets.transfer.user;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class CustomUserDetails extends User {
|
||||
|
||||
private com.baeldung.springsecuredsockets.domain.User user;
|
||||
|
||||
public CustomUserDetails(com.baeldung.springsecuredsockets.domain.User user, Collection<? extends GrantedAuthority> authorities) {
|
||||
super(user.getUsername(), user.getPassword(), authorities);
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public CustomUserDetails(com.baeldung.springsecuredsockets.domain.User user, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
|
||||
super(user.getUsername(), user.getPassword(), enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public com.baeldung.springsecuredsockets.domain.User getUser() {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user