Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User system #4

Merged
merged 4 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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