1
+ package no.nais.cloud.testnais.sandbox.bachelorurlforkorter.auth
2
+
3
+ import com.fasterxml.jackson.annotation.JsonCreator
4
+ import com.fasterxml.jackson.annotation.JsonProperty
5
+ import com.nimbusds.jose.JWSAlgorithm
6
+ import com.nimbusds.jose.JWSHeader
7
+ import com.nimbusds.jose.JWSVerifier
8
+ import com.nimbusds.jose.crypto.MACSigner
9
+ import com.nimbusds.jose.crypto.MACVerifier
10
+ import com.nimbusds.jwt.JWTClaimsSet
11
+ import com.nimbusds.jwt.SignedJWT
12
+ import io.javalin.http.Context
13
+ import io.javalin.http.UnauthorizedResponse
14
+ import jakarta.servlet.http.Cookie
15
+ import mu.KotlinLogging
16
+ import no.nais.cloud.testnais.sandbox.bachelorurlforkorter.Rolle
17
+ import java.net.URLDecoder
18
+ import java.net.URLEncoder
19
+ import java.nio.charset.StandardCharsets
20
+ import java.util.Date
21
+
22
+ data class LoginRequest @JsonCreator constructor(
23
+ @JsonProperty(" username" ) val username : String ,
24
+ @JsonProperty(" password" ) val password : String
25
+ )
26
+
27
+ private val logger = KotlinLogging .logger {}
28
+
29
+ object Auth {
30
+
31
+ private const val SECRET_KEY = " U29tZXN1cGVyc2VjdXJlcGFzc3BocmFzZQ==\n "
32
+ private const val TOKEN_EXPIRATION_TIME = 1000 * 60 * 60
33
+
34
+ fun loggInn (ctx : Context ) {
35
+ val loginRequest = ctx.bodyAsClass(LoginRequest ::class .java)
36
+ val user = UserRepository .findByUsername(loginRequest.username)
37
+ ? : throw UnauthorizedResponse (" Invalid credentials" )
38
+
39
+ if (! verifyPassword(loginRequest.password, user.hashedPassword)) {
40
+ throw UnauthorizedResponse (" Invalid credentials" )
41
+ }
42
+
43
+ val token = createJwtToken(user)
44
+
45
+ val encodedToken = URLEncoder .encode(token, StandardCharsets .UTF_8 .toString())
46
+
47
+ ctx.header(" Set-Cookie" ,
48
+ " session_token=$encodedToken ; Path=/; Max-Age=${TOKEN_EXPIRATION_TIME / 3600 } ; Secure; HttpOnly; SameSite=Strict"
49
+ )
50
+
51
+ logger.info(" Innlogging suksessfull for: {}" , loginRequest.username)
52
+
53
+ ctx.status(204 )
54
+ }
55
+
56
+ fun hentInnloggetBruker (ctx : Context ): Context {
57
+ val token = ctx.cookie(" session_token" ) ? : return ctx.status(401 )
58
+
59
+ val decodedToken = URLDecoder .decode(token, StandardCharsets .UTF_8 .toString())
60
+ val signedJWT = SignedJWT .parse(decodedToken)
61
+
62
+ val expiration = signedJWT.jwtClaimsSet.expirationTime
63
+ if (expiration.before(Date ())) {
64
+ return ctx.status(401 )
65
+ }
66
+
67
+ val username = signedJWT.jwtClaimsSet.subject
68
+ return ctx.status(200 ).json(mapOf (" username" to username))
69
+ }
70
+
71
+
72
+ fun loggUt (ctx : Context ) {
73
+ ctx.removeCookie(" session_token" )
74
+ ctx.status(204 )
75
+ }
76
+
77
+
78
+ fun createJwtToken (user : User ): String {
79
+ val signer = MACSigner (SECRET_KEY .toByteArray()) // HMAC signer
80
+
81
+ val jwtClaims = JWTClaimsSet .Builder ()
82
+ .subject(user.username)
83
+ .claim(" role" , user.role.name)
84
+ .issueTime(Date ())
85
+ .expirationTime(Date (System .currentTimeMillis() + TOKEN_EXPIRATION_TIME ))
86
+ .issuer(" n.av" )
87
+ .build()
88
+
89
+ val signedJWT = SignedJWT (JWSHeader (JWSAlgorithm .HS256 ), jwtClaims)
90
+ signedJWT.sign(signer)
91
+
92
+ return signedJWT.serialize()
93
+ }
94
+
95
+ fun validateJwtToken (ctx : Context ): Pair <String , Rolle >? {
96
+ val token = ctx.cookie(" session_token" )?.let {
97
+ URLDecoder .decode(it, StandardCharsets .UTF_8 .toString())
98
+ } ? : return null
99
+
100
+ return try {
101
+ val signedJWT = SignedJWT .parse(token)
102
+ val verifier: JWSVerifier = MACVerifier (SECRET_KEY .toByteArray())
103
+
104
+ if (! signedJWT.verify(verifier)) {
105
+ return null // Invalid signature
106
+ }
107
+
108
+ val expiration = signedJWT.jwtClaimsSet.expirationTime
109
+ if (expiration.before(Date ())) {
110
+ return null // Token expired
111
+ }
112
+
113
+ val username = signedJWT.jwtClaimsSet.subject
114
+ val roleName = signedJWT.jwtClaimsSet.getStringClaim(" role" )
115
+ val role = Rolle .valueOf(roleName)
116
+
117
+ Pair (username, role)
118
+ } catch (e: Exception ) {
119
+ logger.warn(" Feil ved validering av session token: {}" , e.message)
120
+ null // Invalid token
121
+ }
122
+ }
123
+
124
+ }
0 commit comments