Skip to content

Commit

Permalink
Merged in #9_Add_spring_security (pull request #12)
Browse files Browse the repository at this point in the history
#9 Add spring security

* #9 copy spring security files from my_stuff

* #9 changing tests

* git ignore

* #9 delete Device

* #9 AuthDetails now implements UserDetails

* #9 change userdetails service to auth details service

* #9 add model mapper & fixsome test

* #9 merge

* #9 modelMapper modification

* #9 rename webConfig to ModelMapperConfig

* #9 small changes

* #9 rename userDto to AuthDetails

* #9 add serialVersionUuid to user

* #9 cleaning

* #9 test fixes

Approved-by: Maxim Levitskiy <[email protected]>
  • Loading branch information
UdjinSkobelev authored and Max-Levitskiy committed Jul 18, 2018
1 parent 82bb4e8 commit e8e4d2b
Show file tree
Hide file tree
Showing 30 changed files with 1,148 additions and 58 deletions.
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
*.iml

# System Files
.DS_Store
Thumbs.db
29 changes: 22 additions & 7 deletions back/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/libs-snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>

<dependencies>
Expand All @@ -41,14 +49,15 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- <dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>-->
<!-- <dependency>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mobile</artifactId>
</dependency>-->
<version>2.0.0.M3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
Expand All @@ -71,12 +80,18 @@
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<!--<dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt.version}</version>
</dependency>-->
<!-- https://mvnrepository.com/artifact/org.cassandraunit/cassandra-unit -->
</dependency>
<!-- https://mvnrepository.com/artifact/org.modelmapper/modelmapper -->
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.1.0</version>
</dependency>



<!--Test-->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.webtree.trust.advice;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;

import java.util.Locale;

/**
* Created by Udjin on 21.03.2018.
*/
@ControllerAdvice(annotations = RestController.class)
public class SecurityControllerAdvice {

private MessageSource messageSource;
private static final String LOGIN_ERROR = "login.badCredentials";

@Autowired
public SecurityControllerAdvice(MessageSource messageSource) {
this.messageSource = messageSource;
}

@ExceptionHandler(InternalAuthenticationServiceException.class)
public ResponseEntity<String> badUserNameHandler() {
return createError(LOGIN_ERROR);
}

@ExceptionHandler(BadCredentialsException.class)
public ResponseEntity<String> badPasswordHandler() {
return createError(LOGIN_ERROR);
}

private ResponseEntity<String> createError(String errorCode) {
String errorMessage = messageSource.getMessage(errorCode, new Object[]{}, Locale.getDefault());
return new ResponseEntity<>(errorMessage, new HttpHeaders(), HttpStatus.UNAUTHORIZED);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.webtree.trust.common.utils;

import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class TimeProvider {
public Date now() {
return new Date();
}
}
39 changes: 39 additions & 0 deletions back/src/main/java/org/webtree/trust/config/ModelMapperConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.webtree.trust.config;


import org.modelmapper.ModelMapper;
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.crypto.password.PasswordEncoder;

import org.webtree.trust.domain.User;
import org.webtree.trust.domain.AuthDetals;


@ComponentScan("org.webtree.trust")
@Configuration()
public class ModelMapperConfig {

@Autowired
private PasswordEncoder passwordEncoder;

@Bean
public ModelMapper mapper() {
ModelMapper modelMapper = new ModelMapper();
/* modelMapper.addConverter(new UserDTOToUserConverter(passwordEncoder()));*/
modelMapper.createTypeMap(AuthDetals.class, User.class).addMappings(
mapper ->
mapper
.using(ctx -> {
String encodedPass = ctx.getSource().toString();
return passwordEncoder.encode(encodedPass);
})
.map(AuthDetals::getPassword, User::setPassword)
);
return modelMapper;
}
}
90 changes: 90 additions & 0 deletions back/src/main/java/org/webtree/trust/config/SecurityConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package org.webtree.trust.config;

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.AuthenticationManager;
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.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.webtree.trust.security.JwtAuthenticationEntryPoint;
import org.webtree.trust.security.JwtAuthenticationTokenFilter;
import org.webtree.trust.security.JwtTokenUtil;
import org.webtree.trust.service.UserService;

@ComponentScan("org.webtree.trust")
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

private final UserService userService;
private final JwtTokenUtil tokenUtil;
private final JwtAuthenticationEntryPoint unauthorizedHandler;

@Autowired
public SecurityConfig(UserService userService, JwtTokenUtil tokenUtil, JwtAuthenticationEntryPoint unauthorizedHandler) {
this.userService = userService;
this.tokenUtil = tokenUtil;
this.unauthorizedHandler = unauthorizedHandler;
}

@Autowired
public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder, UserService userService) throws Exception {

authenticationManagerBuilder
.userDetailsService(userService)
.passwordEncoder(passwordEncoder());

}

@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

@Bean
public JwtAuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
return new JwtAuthenticationTokenFilter(userService, tokenUtil);
}

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
// we don't need CSRF because our token is invulnerable
.csrf().disable()
.cors().and()

.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()

// don't create session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()

.authorizeRequests()
//.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()

.antMatchers("/rest/token/new", "/rest/user/register").permitAll()
.anyRequest().authenticated();

// Custom JWT based security filter
httpSecurity
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);

// disable page caching
httpSecurity.headers().cacheControl();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.webtree.trust.controller;

import org.springframework.web.bind.annotation.CrossOrigin;

@CrossOrigin(origins = "${frontend.origins}")
public class AbstractController {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package org.webtree.trust.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import org.webtree.trust.domain.AuthDetals;
import org.webtree.trust.domain.User;
import org.webtree.trust.security.JwtTokenUtil;
import org.webtree.trust.service.UserService;

import javax.servlet.http.HttpServletRequest;

@RestController
@RequestMapping("/rest")
public class SecurityController extends AbstractController {

private final AuthenticationManager authenticationManager;

@Value("${jwt.header}")
private String tokenHeader;

private JwtTokenUtil jwtTokenUtil;
private UserService userService;

@Autowired
public SecurityController(AuthenticationManager authenticationManager, JwtTokenUtil jwtTokenUtil, UserService userService) {
this.authenticationManager = authenticationManager;
this.jwtTokenUtil = jwtTokenUtil;
this.userService = userService;
}

@PostMapping("${jwt.route.authentication.path}")
public ResponseEntity<?> login(@RequestBody AuthDetals authDetals/*, Device device*/) {
Authentication authentication =
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(
authDetals.getUsername(), authDetals.getPassword()));

SecurityContextHolder.getContext().setAuthentication(authentication);

User user = userService.loadUserByUsername(authDetals.getUsername());
return ResponseEntity.ok(jwtTokenUtil.generateToken(user/*, device)*/));
}

@PostMapping
@RequestMapping(value = "${jwt.route.authentication.refresh}", method = RequestMethod.GET)
public ResponseEntity<?> refreshAndGetAuthenticationToken(HttpServletRequest request) {
String token = request.getHeader(tokenHeader);
String username = jwtTokenUtil.getUsernameFromToken(token);
User user = userService.loadUserByUsername(username);

if (jwtTokenUtil.canTokenBeRefreshed(token, user.getLastPasswordResetDate())) {
String refreshedToken = jwtTokenUtil.refreshToken(token);
return ResponseEntity.ok(refreshedToken);
} else {
return ResponseEntity.badRequest().build();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,26 +1,32 @@
package org.webtree.trust.controller;

import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.webtree.trust.domain.AuthDetals;
import org.webtree.trust.domain.User;

import org.webtree.trust.service.UserService;

@RestController
@RequestMapping("/rest/user")
public class UserController {
public class UserController extends AbstractController {

private UserService userService;
private ModelMapper modelMapper;

@Autowired
public UserController(UserService userService) {
public UserController(UserService userService, ModelMapper modelMapper) {
this.userService = userService;
this.modelMapper = modelMapper;
}

@PostMapping("register")
public ResponseEntity<?> doRegister(@RequestBody User user) {
public ResponseEntity<?> doRegister( @RequestBody AuthDetals authDetals) {
User user = modelMapper.map(authDetals, User.class);
user.enable();
if (userService.saveIfNotExists(user)) {
return new ResponseEntity(HttpStatus.CREATED);
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
package org.webtree.trust.controller.alfa;

import org.springframework.context.annotation.Profile;
import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.webtree.trust.controller.UserController;

import org.webtree.trust.provider.Provider;

import javax.servlet.http.HttpServletRequest;

@CrossOrigin
@RestController
@RequestMapping("/rest/alfa")
public class TrustController {
Expand Down
Loading

0 comments on commit e8e4d2b

Please sign in to comment.