Skip to content

Commit

Permalink
Merge pull request #4 from ONAV-KEA/user-system
Browse files Browse the repository at this point in the history
User system
  • Loading branch information
nicolaiandersson authored Nov 30, 2023
2 parents 1b19fa5 + 1abf2ba commit f1d77a7
Show file tree
Hide file tree
Showing 17 changed files with 591 additions and 3 deletions.
36 changes: 36 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,46 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<includes>
<include>Sample.java</include>
</includes>

</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package dk.kea.onav2ndproject_rest;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.Serializable;

@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint,
Serializable {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException {
System.out.println("JwtAuthenticationEntryPoint commence");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,"Unauthorized");
}
}
59 changes: 59 additions & 0 deletions src/main/java/dk/kea/onav2ndproject_rest/JwtFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package dk.kea.onav2ndproject_rest;

import dk.kea.onav2ndproject_rest.service.JwtUserDetailsService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import lombok.AllArgsConstructor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

@AllArgsConstructor
@Component
public class JwtFilter extends OncePerRequestFilter {
private JwtUserDetailsService userDetailsService;
private JwtTokenManager jwtTokenManager;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String tokenHeader = request.getHeader("Authorization");
System.out.println("JwtFilter doFilterInternal call 3 request header" + tokenHeader ); // + JwtController.printHeader(request)
String username = null;
String token = null;
if (tokenHeader != null && tokenHeader.startsWith("Bearer ")) {
token = tokenHeader.substring(7);
try {
username = jwtTokenManager.getUsernameFromToken(token);
} catch (Exception e) {
System.out.println("Unable to get JWT Token");
}
} else {
System.out.println("String does not start with Bearer or tokenheader == NULL");
}
validateToken(request, username, token);
filterChain.doFilter(request, response); //possible: response.setHeader( "key",value); its up to you.
}

private void validateToken(HttpServletRequest request, String username, String token) {
if (null != username && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (jwtTokenManager.validateJwtToken(token, userDetails)) {
UsernamePasswordAuthenticationToken
authenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null,
userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
}
}
71 changes: 71 additions & 0 deletions src/main/java/dk/kea/onav2ndproject_rest/JwtTokenManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package dk.kea.onav2ndproject_rest;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class JwtTokenManager {
public static final long TOKEN_VALIDITY = 10 * 60 * 60 * 1000; // 10 timer
// aha: Below is the server's private key. Which is used to generate new tokens. Length: Minimum 512 bits.
// Which corresponds to minimum 86 characters in cleartext.
@Value("${secret}")
private String jwtSecret;
public String generateJwtToken(UserDetails userDetails) {
System.out.println("TokenManager generateJwtToken(UserDetails) call: 7");
Map<String, Object> claims = new HashMap<>();
return Jwts.builder().setClaims(claims).setSubject(userDetails.getUsername())
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + TOKEN_VALIDITY ))
.signWith(getSignInKey(),SignatureAlgorithm.HS512 )
.compact();
//.signWith(SignatureAlgorithm.HS512, jwtSecret).compact(); // before Spring 3
}

private Key getSignInKey() {
byte[] keyBytes = Decoders.BASE64.decode(jwtSecret);
return Keys.hmacShaKeyFor(keyBytes);
}
public Boolean validateJwtToken(String token, UserDetails userDetails) {
System.out.println("TokenManager validateJwtToken(String token, UserDetails) With token: Call: B");
String username = getUsernameFromToken(token);
Claims claims = getClaims(token);
Boolean isTokenExpired = claims.getExpiration().before(new Date());
return (username.equals(userDetails.getUsername()) && !isTokenExpired);
}
public String getUsernameFromToken(String token) {
System.out.println("TokenManager getUsernameFromToken(String token) With token: Call: A");
//Claims claims = Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody(); // before Spring 3
Claims claims = getClaims(token);
if(claims != null){
return claims.getSubject();
}else {
return "no user found";
}
}

private Claims getClaims(String token){
try{
Claims claims = Jwts
.parserBuilder()
.setSigningKey(getSignInKey())
.build()
.parseClaimsJws(token)
.getBody();
return claims;
}catch (Exception e){
System.out.println("could not parse JWT token for claims");
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import org.springframework.web.bind.annotation.*;

@RestController
@CrossOrigin(origins = "*")
@RequestMapping("/api/event")
public class EventController {

Expand Down
95 changes: 95 additions & 0 deletions src/main/java/dk/kea/onav2ndproject_rest/api/UserController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package dk.kea.onav2ndproject_rest.api;

import dk.kea.onav2ndproject_rest.JwtTokenManager;
import dk.kea.onav2ndproject_rest.entity.JwtRequestModel;
import dk.kea.onav2ndproject_rest.entity.JwtResponseModel;
import dk.kea.onav2ndproject_rest.entity.User;
import dk.kea.onav2ndproject_rest.service.IUserService;
import dk.kea.onav2ndproject_rest.service.JwtUserDetailsService;
import dk.kea.onav2ndproject_rest.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api/user")
public class UserController {
@Autowired
private JwtUserDetailsService userDetailsService;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtTokenManager jwtTokenManager;
@Autowired
private IUserService userService;

@PostMapping("/signup")
public ResponseEntity<JwtResponseModel> signup(@RequestBody JwtRequestModel request){
System.out.println("signup: username:" + request.getUsername() + " password: " + request.getPassword() );
User user = new User(request.getUsername(),request.getPassword());
if(userService.findByName(user.getUsername()).size()==0) {
if (userService.save(user) != null) {
return ResponseEntity.ok(new JwtResponseModel("created user: " + user.getUsername() + " pw: " + user.getPassword()));
} else {
return ResponseEntity.ok(new JwtResponseModel("error creating user: " + user.getUsername()));
}
}else {
return ResponseEntity.ok(new JwtResponseModel("error: user exists: " + user.getUsername()));
}
}

@PostMapping("/login")
public ResponseEntity<JwtResponseModel> createToken(@RequestBody JwtRequestModel request) throws Exception {
// HttpServletRequest servletRequest is available from Spring, if needed.
System.out.println(" JwtController createToken Call: 4" + request.getUsername());
try {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(request.getUsername(),
request.getPassword())
);
} catch (DisabledException e) {
throw new Exception("USER_DISABLED", e);
} catch (BadCredentialsException e) {
return ResponseEntity.ok(new JwtResponseModel("bad credentials"));
}
final UserDetails userDetails = userDetailsService.loadUserByUsername(request.getUsername());
final String jwtToken = jwtTokenManager.generateJwtToken(userDetails);
return ResponseEntity.ok(new JwtResponseModel(jwtToken));
}


@PostMapping("/getSecret")
public ResponseEntity<Map> getSecret() {
System.out.println("getSecret is called");
Map<String,String > map = new HashMap<>();
map.put("message","this is secret from server");
return ResponseEntity.ok(map);
}

@DeleteMapping("/deleteUser")
public ResponseEntity<Map> deleteUser(@RequestBody User user) {
System.out.println("deleteUser is called with user: " + user.getUsername());
List<User> users = userService.findByName(user.getUsername());
User userToDelete = users.get(0);
userService.delete(userToDelete);
Map<String,String > map = new HashMap<>();
map.put("message","user deleted, if found " + user.getUsername());
return ResponseEntity.ok(map);
}

@GetMapping()
public ResponseEntity<User> getUserByToken(@RequestParam String token){
System.out.println("getUserByToken is called with token: " + token);
User user = userService.findByToken(token);
return ResponseEntity.ok(user);
}
}
69 changes: 69 additions & 0 deletions src/main/java/dk/kea/onav2ndproject_rest/config/InitData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package dk.kea.onav2ndproject_rest.config;

import dk.kea.onav2ndproject_rest.entity.Role;
import dk.kea.onav2ndproject_rest.entity.User;
import dk.kea.onav2ndproject_rest.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import java.util.Random;

@Component
public class InitData implements CommandLineRunner {

@Autowired
UserRepository userRepository;

@Autowired
private PasswordEncoder passwordEncoder;

@Override
public void run(String... args) throws Exception {
User user1 = new User();
user1.setName("Anders");
user1.setId(31);
user1.setEmail("[email protected]");
user1.setRole(Role.EMPLOYEE);
user1.setPassword(passwordEncoder.encode("1234"));
user1.setUsername("anders");
userRepository.save(user1);

User user2 = new User();
user2.setName("Benny");
user2.setId(32);
user2.setEmail("[email protected]");
user2.setRole(Role.MANAGER);
user2.setPassword(passwordEncoder.encode("5678"));
user2.setUsername("benny");
userRepository.save(user2);

User user3 = new User();
user3.setName("Carla");
user3.setId(33);
user3.setEmail("[email protected]");
user3.setRole(Role.EMPLOYEE);
user3.setPassword(passwordEncoder.encode("9012"));
user3.setUsername("carla");
userRepository.save(user3);

User user4 = new User();
user4.setName("Dennis");
user4.setId(34);
user4.setEmail("[email protected]");
user4.setRole(Role.HEADCHEF);
user4.setPassword(passwordEncoder.encode("3456"));
user4.setUsername("dennis");
userRepository.save(user4);

User user5 = new User();
user5.setName("Eva");
user5.setId(35);
user5.setEmail("[email protected]");
user5.setRole(Role.EMPLOYEE);
user5.setPassword(passwordEncoder.encode("7890"));
user5.setUsername("eva");
userRepository.save(user5);
}
}
Loading

0 comments on commit f1d77a7

Please sign in to comment.