diff --git a/pom.xml b/pom.xml
index e08bead..802138e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -64,10 +64,46 @@
spring-boot-starter-test
test
+
+ io.jsonwebtoken
+ jjwt-impl
+ 0.11.5
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ 0.11.5
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ runtime
+ true
+
+
+ org.springframework.security
+ spring-security-test
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.0.0-M5
+
+
+ Sample.java
+
+
+
+
org.springframework.boot
spring-boot-maven-plugin
diff --git a/src/main/java/dk/kea/onav2ndproject_rest/JwtAuthenticationEntryPoint.java b/src/main/java/dk/kea/onav2ndproject_rest/JwtAuthenticationEntryPoint.java
new file mode 100644
index 0000000..d62a87d
--- /dev/null
+++ b/src/main/java/dk/kea/onav2ndproject_rest/JwtAuthenticationEntryPoint.java
@@ -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");
+ }
+}
diff --git a/src/main/java/dk/kea/onav2ndproject_rest/JwtFilter.java b/src/main/java/dk/kea/onav2ndproject_rest/JwtFilter.java
new file mode 100644
index 0000000..e2c34cd
--- /dev/null
+++ b/src/main/java/dk/kea/onav2ndproject_rest/JwtFilter.java
@@ -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);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dk/kea/onav2ndproject_rest/JwtTokenManager.java b/src/main/java/dk/kea/onav2ndproject_rest/JwtTokenManager.java
new file mode 100644
index 0000000..00ed4f8
--- /dev/null
+++ b/src/main/java/dk/kea/onav2ndproject_rest/JwtTokenManager.java
@@ -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 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;
+ }
+}
diff --git a/src/main/java/dk/kea/onav2ndproject_rest/api/EventController.java b/src/main/java/dk/kea/onav2ndproject_rest/api/EventController.java
index 54ed450..8b23583 100644
--- a/src/main/java/dk/kea/onav2ndproject_rest/api/EventController.java
+++ b/src/main/java/dk/kea/onav2ndproject_rest/api/EventController.java
@@ -12,7 +12,6 @@
import org.springframework.web.bind.annotation.*;
@RestController
-@CrossOrigin(origins = "*")
@RequestMapping("/api/event")
public class EventController {
diff --git a/src/main/java/dk/kea/onav2ndproject_rest/api/UserController.java b/src/main/java/dk/kea/onav2ndproject_rest/api/UserController.java
new file mode 100644
index 0000000..6fe8a0b
--- /dev/null
+++ b/src/main/java/dk/kea/onav2ndproject_rest/api/UserController.java
@@ -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 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 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