diff --git a/build.gradle b/build.gradle index 62a8c2c..9ac2ca4 100644 --- a/build.gradle +++ b/build.gradle @@ -35,7 +35,20 @@ dependencies { //JSON Parser implementation 'com.google.code.gson:gson:2.8.5' + + //compile 'org.springframework.boot:spring-boot-starter-tomcat' + //compile 'org.springframework.boot:spring-boot-starter-security' + //compile 'org.springframework.boot:spring-boot-starter-actuator' + //compile 'org.springframework.boot:spring-boot-starter-aop' + //ompile group: 'org.springframework.boot', name: 'spring-boot-starter-mail', version: '1.2.0.RELEASE' + compile group: 'org.springframework.security', name: 'spring-security-core', version: '5.1.4.RELEASE' + compile group: 'at.favre.lib', name: 'bcrypt', version: '{latest-version}' + + //JWT + compile 'io.jsonwebtoken:jjwt-api:0.10.5' + runtime 'io.jsonwebtoken:jjwt-impl:0.10.5', + 'io.jsonwebtoken:jjwt-jackson:0.10.5' } diff --git a/src/main/java/hhn/labsw/bugageocaching/Application.java b/src/main/java/hhn/labsw/bugageocaching/Application.java index 8362492..3a6de76 100644 --- a/src/main/java/hhn/labsw/bugageocaching/Application.java +++ b/src/main/java/hhn/labsw/bugageocaching/Application.java @@ -3,11 +3,19 @@ package hhn.labsw.bugageocaching; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; -@SpringBootApplication -public class Application { +@SpringBootApplication(exclude = { SecurityAutoConfiguration.class }) +public class Application{ - public static void main(String[] args) { + /**@Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(Application.class); + }**/ + + public static void main(String[] args) throws Exception { SpringApplication.run(Application.class, args); } } diff --git a/src/main/java/hhn/labsw/bugageocaching/controller/Controller.java b/src/main/java/hhn/labsw/bugageocaching/controller/Controller.java index 4928476..a97359a 100644 --- a/src/main/java/hhn/labsw/bugageocaching/controller/Controller.java +++ b/src/main/java/hhn/labsw/bugageocaching/controller/Controller.java @@ -5,14 +5,24 @@ import com.google.gson.GsonBuilder; import hhn.labsw.bugageocaching.entities.*; import hhn.labsw.bugageocaching.exceptions.IllegalParameterException; import hhn.labsw.bugageocaching.repositories.*; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.security.Keys; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.crypto.bcrypt.BCrypt; import org.springframework.web.bind.annotation.*; +import javax.annotation.PostConstruct; +import javax.xml.bind.DatatypeConverter; +import java.security.Key; +import java.security.SecureRandom; import java.util.*; import java.util.concurrent.atomic.AtomicLong; +import java.util.logging.Logger; @RestController public class Controller { @@ -39,6 +49,13 @@ public class Controller { UserRepository userRepository; private AtomicLong counter = new AtomicLong(); + byte[] key = new byte[64]; + + @PostConstruct + public void init() { + new SecureRandom().nextBytes(key); + System.out.println(Arrays.toString(key)); + } @CrossOrigin(origins = "http://localhost:8081") // only for dev purpose @RequestMapping("/api/allCaches") @@ -60,14 +77,37 @@ public class Controller { return ResponseEntity.status(404).body("User was not found"); } + SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; + if (BCrypt.checkpw(user.getPassword(), userRepository.findByUsername(user.getUsername()).getPassword())) { + String token = Jwts.builder() + .setSubject(user.getUsername()) + .claim("admin", userRepository.findByUsername(user.getUsername()).getRoles().stream().anyMatch(x -> x.getId() == 0)) //True if user is admin + .setExpiration(new Date(new Date().getTime() + (1000 * 60 * 60 * 24))) //One day expiration + .signWith(signatureAlgorithm, key) + .compact(); + System.out.println(token); + + Claims claims = Jwts.parser() //Parse JWT + .setSigningKey(key) + .parseClaimsJws(token).getBody(); + System.out.println("ID: " + claims.getId()); + System.out.println("Subject: " + claims.getSubject()); + System.out.println("Issuer: " + claims.getIssuer()); + System.out.println("Admin: " + claims.get("admin")); + System.out.println("Expiration: " + claims.getExpiration()); + + return ResponseEntity.status(200).body(token); + } + + /*if (BCrypt.checkpw(user.getPassword(), userRepository.findByUsername(user.getUsername()).getPassword())) { String token = user.getUsername() + BCrypt.hashpw(String.valueOf(System.currentTimeMillis() + counter.incrementAndGet()), BCrypt.gensalt()); String hashedToken = BCrypt.hashpw(token, BCrypt.gensalt()); userRepository.findByUsername(user.getUsername()).setToken(hashedToken); userRepository.save(userRepository.findByUsername(user.getUsername())); //return ResponseEntity.ok(new Gson().toJson(token)); return ResponseEntity.status(200).body(token); - } + }*/ return ResponseEntity.status(400).body("Es ist ein Fehler aufgetreten"); } @@ -81,16 +121,22 @@ public class Controller { Bearbeitet bearbeitet = new Bearbeitet(); - User user = userRepository.findByUsername(token.substring(0, token.indexOf("$"))); - if (user == null) { - return ResponseEntity.status(404).body("User was not found"); - } - bearbeitet.setUser(user); + try { + Claims claims = Jwts.parser() //Parse JWT + .setSigningKey(key) + .parseClaimsJws(token).getBody(); - Optional cacheOptional = cacheRepository.findById(Integer.valueOf(cacheID)); - if (cacheOptional.isPresent()) { - Cache cache = cacheOptional.get(); - bearbeitet.setCache(cache); + + User user = userRepository.findByUsername(claims.getSubject()); + if (user == null) { + return ResponseEntity.status(404).body("User was not found"); + } + bearbeitet.setUser(user); + + Optional cacheOptional = cacheRepository.findById(Integer.valueOf(cacheID)); + if (cacheOptional.isPresent()) { + Cache cache = cacheOptional.get(); + bearbeitet.setCache(cache); Station startStation = cache.getStationen().get(0); bearbeitet.setAktuelleStation(startStation); @@ -107,9 +153,14 @@ public class Controller { return ResponseEntity.status(404).body("There is no cacheAccesDefinition with the ID " + 0); } - bearbeitetRepository.save(bearbeitet); + bearbeitetRepository.save(bearbeitet); - return ResponseEntity.status(200).body(new Gson().toJson(bearbeitet)); + return ResponseEntity.status(200).body(new Gson().toJson(bearbeitet)); + } catch (ExpiredJwtException e) { + return ResponseEntity.status(400).body("JWT Token expired"); + } catch (Exception e){ + return ResponseEntity.status(400).body("JWT Token invalid"); + } } else { // kein angemeldeter User startet den cache(es wird nur der cache als parameter übergeben) Optional cacheOptional = cacheRepository.findById(Integer.valueOf(cacheID)); @@ -122,19 +173,20 @@ public class Controller { } } + //Eigentlich brauchen wir mit JWT keine Logout Methode mehr. @CrossOrigin(origins = "http://localhost:8081") // only for dev purpose @RequestMapping("/api/logout") @ResponseBody public ResponseEntity logout(@RequestParam String token) { // System.out.println("logout"); - User user = userRepository.findByUsername(token.substring(0, token.indexOf("$"))); + /*User user = userRepository.findByUsername(token.substring(0, token.indexOf("$"))); // System.out.println(token); // System.out.println(user.getToken()); if (user == null || user.getToken().isEmpty()) { return ResponseEntity.status(404).body("User was not found"); } user.setToken(null); - userRepository.save(user); + userRepository.save(user);*/ return ResponseEntity.status(200).body("Token was deleted"); } @@ -226,7 +278,20 @@ public class Controller { @RequestMapping("/api/checkAdmin") @ResponseBody public ResponseEntity checkAdmin(@RequestParam String token) { - User user = userRepository.findByUsername(token.substring(0, token.indexOf("$"))); + + try { + Claims claims = Jwts.parser() //Parse JWT + .setSigningKey(key) + .parseClaimsJws(token).getBody(); + + return ResponseEntity.status(200).body(claims.get("admin")); + }catch (ExpiredJwtException e) { + return ResponseEntity.status(400).body("JWT Token expired"); + } catch (Exception e){ + return ResponseEntity.status(400).body("JWT Token invalid"); + } + + /*User user = userRepository.findByUsername(token.substring(0, token.indexOf("$"))); if (user == null) { return ResponseEntity.status(404).body("User was not found"); } @@ -235,7 +300,7 @@ public class Controller { return ResponseEntity.status(200).body("User is Admin"); } } - return ResponseEntity.status(401).body("User is no Admin"); + return ResponseEntity.status(401).body("User is no Admin");*/ } //Bis hier @@ -273,7 +338,14 @@ public class Controller { @ResponseBody public ResponseEntity getMyCaches(@RequestParam String token) { try { - User user = userRepository.findByUsername(token.substring(0, token.indexOf("$"))); + + Claims claims = Jwts.parser() //Parse JWT + .setSigningKey(key) + .parseClaimsJws(token).getBody(); + + + User user = userRepository.findByUsername(claims.getSubject()); + if (user != null) { ArrayList bearbeitetList = new ArrayList<>(); @@ -286,8 +358,10 @@ public class Controller { } else { return ResponseEntity.status(404).body("User was not found in the database"); } - } catch (StringIndexOutOfBoundsException e) { - return ResponseEntity.status(400).body("Invalid token"); + } catch (ExpiredJwtException e) { + return ResponseEntity.status(400).body("JWT Token expired"); + } catch (Exception e){ + return ResponseEntity.status(400).body("JWT Token invalid"); } } @@ -314,14 +388,21 @@ public class Controller { @ResponseBody public ResponseEntity getUser(@RequestParam String token) { try { - User user = userRepository.findByUsername(token.substring(0, token.indexOf("$"))); + Claims claims = Jwts.parser() //Parse JWT + .setSigningKey(key) + .parseClaimsJws(token).getBody(); + + + User user = userRepository.findByUsername(claims.getSubject()); if (user != null) { return ResponseEntity.status(200).body(new Gson().toJson(user)); } else { return ResponseEntity.status(404).body("User was not found in the database"); } - } catch (StringIndexOutOfBoundsException e) { - return ResponseEntity.status(400).body("Invalid token"); + } catch (ExpiredJwtException e) { + return ResponseEntity.status(400).body("JWT Token expired"); + } catch (Exception e){ + return ResponseEntity.status(400).body("JWT Token invalid"); } } } diff --git a/src/main/java/hhn/labsw/bugageocaching/entities/Role.java b/src/main/java/hhn/labsw/bugageocaching/entities/Role.java index 5019a0b..b5612bc 100644 --- a/src/main/java/hhn/labsw/bugageocaching/entities/Role.java +++ b/src/main/java/hhn/labsw/bugageocaching/entities/Role.java @@ -31,4 +31,9 @@ public class Role { public void setName(String name) { this.name = name; } + + @Override + public String toString() { + return name; + } } diff --git a/src/main/java/hhn/labsw/bugageocaching/entities/User.java b/src/main/java/hhn/labsw/bugageocaching/entities/User.java index ffbed7d..0b546f6 100644 --- a/src/main/java/hhn/labsw/bugageocaching/entities/User.java +++ b/src/main/java/hhn/labsw/bugageocaching/entities/User.java @@ -1,8 +1,12 @@ package hhn.labsw.bugageocaching.entities; import javax.persistence.*; + +import java.util.Set; + import java.util.List; + @Entity @Table public class User { @@ -18,14 +22,17 @@ public class User { private String email; private String password; + @ManyToMany private List roles; - private String token; - @ManyToOne private Team team; + + @Transient + private String passwordConfirm; + public int getId() { return id; } @@ -98,11 +105,4 @@ public class User { this.roles = roles; } - public String getToken() { - return token; - } - - public void setToken(String token) { - this.token = token; - } } diff --git a/src/main/java/hhn/labsw/bugageocaching/repositories/BearbeitetRepository.java b/src/main/java/hhn/labsw/bugageocaching/repositories/BearbeitetRepository.java index fb4a270..ac5484c 100644 --- a/src/main/java/hhn/labsw/bugageocaching/repositories/BearbeitetRepository.java +++ b/src/main/java/hhn/labsw/bugageocaching/repositories/BearbeitetRepository.java @@ -1,7 +1,8 @@ package hhn.labsw.bugageocaching.repositories; import hhn.labsw.bugageocaching.entities.Bearbeitet; +import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.repository.CrudRepository; -public interface BearbeitetRepository extends CrudRepository { +public interface BearbeitetRepository extends JpaRepository { } diff --git a/src/main/java/hhn/labsw/bugageocaching/repositories/CacheAccesDefinitionRepository.java b/src/main/java/hhn/labsw/bugageocaching/repositories/CacheAccesDefinitionRepository.java index 2a01cab..a807947 100644 --- a/src/main/java/hhn/labsw/bugageocaching/repositories/CacheAccesDefinitionRepository.java +++ b/src/main/java/hhn/labsw/bugageocaching/repositories/CacheAccesDefinitionRepository.java @@ -1,7 +1,8 @@ package hhn.labsw.bugageocaching.repositories; import hhn.labsw.bugageocaching.entities.CacheAccesDefinition; +import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.repository.CrudRepository; -public interface CacheAccesDefinitionRepository extends CrudRepository { +public interface CacheAccesDefinitionRepository extends JpaRepository { } diff --git a/src/main/java/hhn/labsw/bugageocaching/repositories/CacheRepository.java b/src/main/java/hhn/labsw/bugageocaching/repositories/CacheRepository.java index b480c64..9ac29b1 100644 --- a/src/main/java/hhn/labsw/bugageocaching/repositories/CacheRepository.java +++ b/src/main/java/hhn/labsw/bugageocaching/repositories/CacheRepository.java @@ -1,7 +1,8 @@ package hhn.labsw.bugageocaching.repositories; import hhn.labsw.bugageocaching.entities.Cache; +import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.repository.CrudRepository; -public interface CacheRepository extends CrudRepository { +public interface CacheRepository extends JpaRepository { } diff --git a/src/main/java/hhn/labsw/bugageocaching/repositories/RewardRepository.java b/src/main/java/hhn/labsw/bugageocaching/repositories/RewardRepository.java index ca51b18..0756cec 100644 --- a/src/main/java/hhn/labsw/bugageocaching/repositories/RewardRepository.java +++ b/src/main/java/hhn/labsw/bugageocaching/repositories/RewardRepository.java @@ -1,7 +1,8 @@ package hhn.labsw.bugageocaching.repositories; import hhn.labsw.bugageocaching.entities.Reward; +import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.repository.CrudRepository; -public interface RewardRepository extends CrudRepository { +public interface RewardRepository extends JpaRepository { } diff --git a/src/main/java/hhn/labsw/bugageocaching/repositories/RoleRepository.java b/src/main/java/hhn/labsw/bugageocaching/repositories/RoleRepository.java new file mode 100644 index 0000000..b5f8798 --- /dev/null +++ b/src/main/java/hhn/labsw/bugageocaching/repositories/RoleRepository.java @@ -0,0 +1,7 @@ +package hhn.labsw.bugageocaching.repositories; + +import hhn.labsw.bugageocaching.entities.Role; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface RoleRepository extends JpaRepository { +} diff --git a/src/main/java/hhn/labsw/bugageocaching/repositories/StationRepository.java b/src/main/java/hhn/labsw/bugageocaching/repositories/StationRepository.java index c902ec5..146c9bb 100644 --- a/src/main/java/hhn/labsw/bugageocaching/repositories/StationRepository.java +++ b/src/main/java/hhn/labsw/bugageocaching/repositories/StationRepository.java @@ -1,7 +1,8 @@ package hhn.labsw.bugageocaching.repositories; import hhn.labsw.bugageocaching.entities.Station; +import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.repository.CrudRepository; -public interface StationRepository extends CrudRepository { +public interface StationRepository extends JpaRepository { } diff --git a/src/main/java/hhn/labsw/bugageocaching/repositories/TeamRepository.java b/src/main/java/hhn/labsw/bugageocaching/repositories/TeamRepository.java index edf1d5d..77c69d9 100644 --- a/src/main/java/hhn/labsw/bugageocaching/repositories/TeamRepository.java +++ b/src/main/java/hhn/labsw/bugageocaching/repositories/TeamRepository.java @@ -1,7 +1,8 @@ package hhn.labsw.bugageocaching.repositories; import hhn.labsw.bugageocaching.entities.Team; +import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.repository.CrudRepository; -public interface TeamRepository extends CrudRepository { +public interface TeamRepository extends JpaRepository { } diff --git a/src/main/java/hhn/labsw/bugageocaching/repositories/UserRepository.java b/src/main/java/hhn/labsw/bugageocaching/repositories/UserRepository.java index 81cddfe..8ab2115 100644 --- a/src/main/java/hhn/labsw/bugageocaching/repositories/UserRepository.java +++ b/src/main/java/hhn/labsw/bugageocaching/repositories/UserRepository.java @@ -1,6 +1,10 @@ package hhn.labsw.bugageocaching.repositories; import hhn.labsw.bugageocaching.entities.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.repository.CrudRepository; + + import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; @@ -12,4 +16,5 @@ public interface UserRepository extends CrudRepository { @Query(value = "SELECT u.id, u.username, u.ranking_points_sum from user u order by ranking_points_sum DESC", nativeQuery = true) List getRankingList(); + }