Refactor authentication
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package com.infendro.account
|
package com.infendro.account
|
||||||
|
|
||||||
import com.infendro.account.config.*
|
import com.infendro.account.config.*
|
||||||
|
import com.infendro.account.config.configureSession
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
import io.ktor.server.cio.*
|
import io.ktor.server.cio.*
|
||||||
|
|
||||||
@@ -13,6 +14,7 @@ fun Application.module() {
|
|||||||
configureValidation()
|
configureValidation()
|
||||||
configureException()
|
configureException()
|
||||||
|
|
||||||
|
configureSession()
|
||||||
configureSecurity()
|
configureSecurity()
|
||||||
configureRouting()
|
configureRouting()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
package com.infendro.account.config
|
package com.infendro.account.config
|
||||||
|
|
||||||
import com.infendro.account.model.Role
|
|
||||||
import com.infendro.account.model.repository.AccountRepository
|
|
||||||
import com.infendro.account.util.PasswordHasher
|
|
||||||
import com.infendro.ktor.migration.Migration
|
import com.infendro.ktor.migration.Migration
|
||||||
|
import initial
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
import org.jetbrains.exposed.v1.jdbc.Database
|
import org.jetbrains.exposed.v1.jdbc.Database
|
||||||
|
|
||||||
@@ -17,56 +15,6 @@ fun Application.configureDatabase() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
install(Migration) {
|
install(Migration) {
|
||||||
migration("initial") {
|
initial()
|
||||||
exec(
|
|
||||||
"""
|
|
||||||
CREATE TABLE access
|
|
||||||
(
|
|
||||||
id BIGSERIAL
|
|
||||||
PRIMARY KEY,
|
|
||||||
token_hash TEXT
|
|
||||||
NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE account
|
|
||||||
(
|
|
||||||
id BIGSERIAL
|
|
||||||
PRIMARY KEY,
|
|
||||||
username TEXT
|
|
||||||
UNIQUE
|
|
||||||
NOT NULL,
|
|
||||||
password_hash TEXT
|
|
||||||
NOT NULL,
|
|
||||||
password_salt TEXT
|
|
||||||
NOT NULL,
|
|
||||||
secret TEXT
|
|
||||||
NOT NULL,
|
|
||||||
role TEXT
|
|
||||||
NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE session
|
|
||||||
(
|
|
||||||
id BIGSERIAL
|
|
||||||
PRIMARY KEY,
|
|
||||||
token_hash TEXT
|
|
||||||
NOT NULL,
|
|
||||||
account_id BIGINT
|
|
||||||
REFERENCES account (id) ON DELETE CASCADE
|
|
||||||
NOT NULL
|
|
||||||
);
|
|
||||||
""".trimIndent(),
|
|
||||||
)
|
|
||||||
|
|
||||||
AccountRepository.insert {
|
|
||||||
val salt = PasswordHasher.generateSalt()
|
|
||||||
|
|
||||||
this.username = "infendro"
|
|
||||||
this.passwordHash = PasswordHasher.hash("password", salt)
|
|
||||||
this.passwordSalt = salt
|
|
||||||
this.secret = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA===="
|
|
||||||
this.role = Role.OWNER
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,14 @@
|
|||||||
package com.infendro.account.config
|
package com.infendro.account.config
|
||||||
|
|
||||||
import com.infendro.account.exception.client.UnauthorizedException
|
|
||||||
import com.infendro.account.model.Role
|
import com.infendro.account.model.Role
|
||||||
import com.infendro.account.model.entity.AccountEntity
|
import com.infendro.account.model.entity.AccountEntity
|
||||||
import com.infendro.account.model.entity.SessionEntity
|
import com.infendro.account.model.entity.SessionEntity
|
||||||
import com.infendro.account.model.entity.SessionTable
|
|
||||||
import com.infendro.account.model.repository.SessionRepository
|
import com.infendro.account.model.repository.SessionRepository
|
||||||
import com.infendro.account.util.Hasher
|
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
import io.ktor.server.auth.*
|
import io.ktor.server.auth.*
|
||||||
import io.ktor.server.sessions.*
|
import io.ktor.server.sessions.*
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import org.jetbrains.exposed.v1.core.eq
|
|
||||||
import kotlin.time.Duration.Companion.days
|
|
||||||
|
|
||||||
@Serializable
|
data class Principal(
|
||||||
data class AuthenticationSession(
|
|
||||||
val token: String,
|
|
||||||
)
|
|
||||||
|
|
||||||
data class AuthenticationPrincipal(
|
|
||||||
val account: AccountEntity,
|
val account: AccountEntity,
|
||||||
val session: SessionEntity,
|
val session: SessionEntity,
|
||||||
) {
|
) {
|
||||||
@@ -28,34 +17,20 @@ data class AuthenticationPrincipal(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun Application.configureSecurity() {
|
fun Application.configureSecurity() {
|
||||||
val config = configuration
|
|
||||||
|
|
||||||
install(Sessions) {
|
|
||||||
cookie<AuthenticationSession>("Authentication") {
|
|
||||||
this.cookie.domain = config.security.cookie.domain
|
|
||||||
this.cookie.path = config.security.cookie.path
|
|
||||||
this.cookie.httpOnly = true
|
|
||||||
this.cookie.secure = config.security.cookie.secure
|
|
||||||
this.cookie.extensions["SameSite"] = "Strict"
|
|
||||||
this.cookie.maxAge = 7.days
|
|
||||||
}
|
|
||||||
}
|
|
||||||
install(Authentication) {
|
install(Authentication) {
|
||||||
session<AuthenticationSession> {
|
bearer {
|
||||||
|
authenticate { credential ->
|
||||||
|
SessionRepository.by(credential.token)?.principal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
session<Session> {
|
||||||
validate { session ->
|
validate { session ->
|
||||||
val session = SessionRepository
|
SessionRepository.by(session.token)?.principal
|
||||||
.singleOrNull { SessionTable.tokenHash eq Hasher.hash(session.token) }
|
?.also { sessions.set(session) }
|
||||||
?: return@validate null
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sessions.set(session)
|
val SessionEntity.principal: Principal
|
||||||
|
get() = Principal(account(), this)
|
||||||
AuthenticationPrincipal(session.account(), session)
|
|
||||||
}
|
|
||||||
challenge {
|
|
||||||
call.sessions.clear<AuthenticationSession>()
|
|
||||||
|
|
||||||
throw UnauthorizedException()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.infendro.account.config
|
||||||
|
|
||||||
|
import io.ktor.server.application.*
|
||||||
|
import io.ktor.server.sessions.*
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlin.time.Duration.Companion.days
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Session(
|
||||||
|
val token: String,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun Application.configureSession() {
|
||||||
|
val config = configuration
|
||||||
|
|
||||||
|
install(Sessions) {
|
||||||
|
cookie<Session>("Authentication") {
|
||||||
|
this.cookie.domain = config.security.cookie.domain
|
||||||
|
this.cookie.path = config.security.cookie.path
|
||||||
|
this.cookie.httpOnly = true
|
||||||
|
this.cookie.secure = config.security.cookie.secure
|
||||||
|
this.cookie.extensions["SameSite"] = "Strict"
|
||||||
|
this.cookie.maxAge = 7.days
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import com.infendro.account.model.Role
|
||||||
|
import com.infendro.account.model.repository.AccountRepository
|
||||||
|
import com.infendro.account.util.PasswordHasher
|
||||||
|
import com.infendro.ktor.migration.MigrationConfig
|
||||||
|
|
||||||
|
fun MigrationConfig.initial() = migration("initial") {
|
||||||
|
exec(
|
||||||
|
"""
|
||||||
|
CREATE TABLE access
|
||||||
|
(
|
||||||
|
id BIGSERIAL
|
||||||
|
PRIMARY KEY,
|
||||||
|
token_hash TEXT
|
||||||
|
NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE account
|
||||||
|
(
|
||||||
|
id BIGSERIAL
|
||||||
|
PRIMARY KEY,
|
||||||
|
username TEXT
|
||||||
|
UNIQUE
|
||||||
|
NOT NULL,
|
||||||
|
password_hash TEXT
|
||||||
|
NOT NULL,
|
||||||
|
password_salt TEXT
|
||||||
|
NOT NULL,
|
||||||
|
secret TEXT
|
||||||
|
NOT NULL,
|
||||||
|
role TEXT
|
||||||
|
NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE session
|
||||||
|
(
|
||||||
|
id BIGSERIAL
|
||||||
|
PRIMARY KEY,
|
||||||
|
token_hash TEXT
|
||||||
|
NOT NULL,
|
||||||
|
account_id BIGINT
|
||||||
|
REFERENCES account (id) ON DELETE CASCADE
|
||||||
|
NOT NULL
|
||||||
|
);
|
||||||
|
""".trimIndent(),
|
||||||
|
)
|
||||||
|
|
||||||
|
AccountRepository.insert {
|
||||||
|
val salt = PasswordHasher.generateSalt()
|
||||||
|
|
||||||
|
this.username = "infendro"
|
||||||
|
this.passwordHash = PasswordHasher.hash("password", salt)
|
||||||
|
this.passwordSalt = salt
|
||||||
|
this.secret = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA===="
|
||||||
|
this.role = Role.OWNER
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,10 @@
|
|||||||
package com.infendro.account.model.repository
|
package com.infendro.account.model.repository
|
||||||
|
|
||||||
import com.infendro.account.model.entity.SessionEntity
|
import com.infendro.account.model.entity.SessionEntity
|
||||||
|
import com.infendro.account.model.entity.SessionTable
|
||||||
|
import com.infendro.account.util.Hasher
|
||||||
|
import org.jetbrains.exposed.v1.core.eq
|
||||||
|
|
||||||
object SessionRepository : Repository<SessionEntity>(SessionEntity)
|
object SessionRepository : Repository<SessionEntity>(SessionEntity) {
|
||||||
|
fun by(token: String) = singleOrNull { SessionTable.tokenHash eq Hasher.hash(token) }
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.infendro.account.routing
|
package com.infendro.account.routing
|
||||||
|
|
||||||
import com.infendro.account.config.AuthenticationPrincipal
|
import com.infendro.account.config.Principal
|
||||||
import com.infendro.account.service.AccessService
|
import com.infendro.account.service.AccessService
|
||||||
import io.ktor.http.HttpStatusCode.Companion.OK
|
import io.ktor.http.HttpStatusCode.Companion.OK
|
||||||
import io.ktor.resources.*
|
import io.ktor.resources.*
|
||||||
@@ -27,21 +27,21 @@ private class Access {
|
|||||||
fun Routing.access() {
|
fun Routing.access() {
|
||||||
authenticate {
|
authenticate {
|
||||||
post<Access> {
|
post<Access> {
|
||||||
val principal = call.principal<AuthenticationPrincipal>()!!
|
val principal = call.principal<Principal>()!!
|
||||||
|
|
||||||
AccessService.post(principal)
|
AccessService.post(principal)
|
||||||
.also { call.respond(it) }
|
.also { call.respond(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
get<Access.All> {
|
get<Access.All> {
|
||||||
val principal = call.principal<AuthenticationPrincipal>()!!
|
val principal = call.principal<Principal>()!!
|
||||||
|
|
||||||
AccessService.getAll(principal)
|
AccessService.getAll(principal)
|
||||||
.also { call.respond(it) }
|
.also { call.respond(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
delete<Access.Id> { resource ->
|
delete<Access.Id> { resource ->
|
||||||
val principal = call.principal<AuthenticationPrincipal>()!!
|
val principal = call.principal<Principal>()!!
|
||||||
val id = resource.id
|
val id = resource.id
|
||||||
|
|
||||||
AccessService.deleteId(principal, id)
|
AccessService.deleteId(principal, id)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.infendro.account.routing
|
package com.infendro.account.routing
|
||||||
|
|
||||||
import com.infendro.account.config.AuthenticationPrincipal
|
import com.infendro.account.config.Principal
|
||||||
import com.infendro.account.dto.request.*
|
import com.infendro.account.dto.request.*
|
||||||
import com.infendro.account.service.AccountService
|
import com.infendro.account.service.AccountService
|
||||||
import io.ktor.http.HttpStatusCode.Companion.OK
|
import io.ktor.http.HttpStatusCode.Companion.OK
|
||||||
@@ -79,28 +79,28 @@ fun Routing.account() {
|
|||||||
|
|
||||||
authenticate {
|
authenticate {
|
||||||
get<Account.All> {
|
get<Account.All> {
|
||||||
val principal = call.principal<AuthenticationPrincipal>()!!
|
val principal = call.principal<Principal>()!!
|
||||||
|
|
||||||
AccountService.getAll(principal)
|
AccountService.getAll(principal)
|
||||||
.also { call.respond(it) }
|
.also { call.respond(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
get<Account.Current> {
|
get<Account.Current> {
|
||||||
val principal = call.principal<AuthenticationPrincipal>()!!
|
val principal = call.principal<Principal>()!!
|
||||||
|
|
||||||
AccountService.getCurrent(principal)
|
AccountService.getCurrent(principal)
|
||||||
.also { call.respond(it) }
|
.also { call.respond(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
delete<Account.Current> {
|
delete<Account.Current> {
|
||||||
val principal = call.principal<AuthenticationPrincipal>()!!
|
val principal = call.principal<Principal>()!!
|
||||||
|
|
||||||
AccountService.deleteCurrent(principal)
|
AccountService.deleteCurrent(principal)
|
||||||
call.respond(OK)
|
call.respond(OK)
|
||||||
}
|
}
|
||||||
|
|
||||||
put<Account.Current.Username> {
|
put<Account.Current.Username> {
|
||||||
val principal = call.principal<AuthenticationPrincipal>()!!
|
val principal = call.principal<Principal>()!!
|
||||||
val request = call.receive<PutAccountCurrentUsernameRequest>()
|
val request = call.receive<PutAccountCurrentUsernameRequest>()
|
||||||
|
|
||||||
AccountService.putCurrentUsername(principal, call.sessions, request)
|
AccountService.putCurrentUsername(principal, call.sessions, request)
|
||||||
@@ -108,7 +108,7 @@ fun Routing.account() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
put<Account.Current.Password> {
|
put<Account.Current.Password> {
|
||||||
val principal = call.principal<AuthenticationPrincipal>()!!
|
val principal = call.principal<Principal>()!!
|
||||||
val request = call.receive<PutAccountCurrentPasswordRequest>()
|
val request = call.receive<PutAccountCurrentPasswordRequest>()
|
||||||
|
|
||||||
AccountService.putCurrentPassword(principal, call.sessions, request)
|
AccountService.putCurrentPassword(principal, call.sessions, request)
|
||||||
@@ -116,7 +116,7 @@ fun Routing.account() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
post<Account.Current.Secret> {
|
post<Account.Current.Secret> {
|
||||||
val principal = call.principal<AuthenticationPrincipal>()!!
|
val principal = call.principal<Principal>()!!
|
||||||
val request = call.receive<PostAccountCurrentSecretRequest>()
|
val request = call.receive<PostAccountCurrentSecretRequest>()
|
||||||
|
|
||||||
AccountService.postCurrentSecret(principal, call.sessions, request)
|
AccountService.postCurrentSecret(principal, call.sessions, request)
|
||||||
@@ -124,14 +124,14 @@ fun Routing.account() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get<Account.Current.Session.All> {
|
get<Account.Current.Session.All> {
|
||||||
val principal = call.principal<AuthenticationPrincipal>()!!
|
val principal = call.principal<Principal>()!!
|
||||||
|
|
||||||
AccountService.getCurrentSessionAll(principal)
|
AccountService.getCurrentSessionAll(principal)
|
||||||
.also { call.respond(it) }
|
.also { call.respond(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
delete<Account.Current.Session.Id> { resource ->
|
delete<Account.Current.Session.Id> { resource ->
|
||||||
val principal = call.principal<AuthenticationPrincipal>()!!
|
val principal = call.principal<Principal>()!!
|
||||||
val id = resource.id
|
val id = resource.id
|
||||||
|
|
||||||
AccountService.deleteCurrentSessionId(principal, call.sessions, id)
|
AccountService.deleteCurrentSessionId(principal, call.sessions, id)
|
||||||
@@ -139,7 +139,7 @@ fun Routing.account() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
delete<Account.Id> { resource ->
|
delete<Account.Id> { resource ->
|
||||||
val principal = call.principal<AuthenticationPrincipal>()!!
|
val principal = call.principal<Principal>()!!
|
||||||
val id = resource.id
|
val id = resource.id
|
||||||
|
|
||||||
AccountService.deleteId(principal, id)
|
AccountService.deleteId(principal, id)
|
||||||
@@ -147,7 +147,7 @@ fun Routing.account() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
put<Account.Id.Role> { resource ->
|
put<Account.Id.Role> { resource ->
|
||||||
val principal = call.principal<AuthenticationPrincipal>()!!
|
val principal = call.principal<Principal>()!!
|
||||||
val id = resource.parent.id
|
val id = resource.parent.id
|
||||||
val request = call.receive<PutAccountIdRoleRequest>()
|
val request = call.receive<PutAccountIdRoleRequest>()
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.infendro.account.routing
|
package com.infendro.account.routing
|
||||||
|
|
||||||
import com.infendro.account.config.AuthenticationPrincipal
|
import com.infendro.account.config.Principal
|
||||||
import com.infendro.account.dto.request.PostSessionRequest
|
import com.infendro.account.dto.request.PostSessionRequest
|
||||||
import com.infendro.account.service.SessionService
|
import com.infendro.account.service.SessionService
|
||||||
import io.ktor.http.HttpStatusCode.Companion.OK
|
import io.ktor.http.HttpStatusCode.Companion.OK
|
||||||
@@ -42,14 +42,14 @@ fun Routing.session() {
|
|||||||
|
|
||||||
authenticate {
|
authenticate {
|
||||||
get<Session.All> {
|
get<Session.All> {
|
||||||
val principal = call.principal<AuthenticationPrincipal>()!!
|
val principal = call.principal<Principal>()!!
|
||||||
|
|
||||||
SessionService.getAll(principal)
|
SessionService.getAll(principal)
|
||||||
.also { call.respond(it) }
|
.also { call.respond(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
delete<Session.Id> { resource ->
|
delete<Session.Id> { resource ->
|
||||||
val principal = call.principal<AuthenticationPrincipal>()!!
|
val principal = call.principal<Principal>()!!
|
||||||
val id = resource.id
|
val id = resource.id
|
||||||
|
|
||||||
SessionService.deleteId(principal, id)
|
SessionService.deleteId(principal, id)
|
||||||
@@ -57,14 +57,14 @@ fun Routing.session() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get<Session.Current> {
|
get<Session.Current> {
|
||||||
val principal = call.principal<AuthenticationPrincipal>()!!
|
val principal = call.principal<Principal>()!!
|
||||||
|
|
||||||
SessionService.getCurrent(principal)
|
SessionService.getCurrent(principal)
|
||||||
.also { call.respond(it) }
|
.also { call.respond(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
delete<Session.Current> {
|
delete<Session.Current> {
|
||||||
val principal = call.principal<AuthenticationPrincipal>()!!
|
val principal = call.principal<Principal>()!!
|
||||||
|
|
||||||
SessionService.deleteCurrent(principal, call.sessions)
|
SessionService.deleteCurrent(principal, call.sessions)
|
||||||
call.respond(OK)
|
call.respond(OK)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.infendro.account.service
|
package com.infendro.account.service
|
||||||
|
|
||||||
import com.infendro.account.config.AuthenticationPrincipal
|
import com.infendro.account.config.Principal
|
||||||
import com.infendro.account.dto.response.AccessResponse
|
import com.infendro.account.dto.response.AccessResponse
|
||||||
import com.infendro.account.dto.response.PostAccessResponse
|
import com.infendro.account.dto.response.PostAccessResponse
|
||||||
import com.infendro.account.dto.response.toResponse
|
import com.infendro.account.dto.response.toResponse
|
||||||
@@ -14,7 +14,7 @@ import com.infendro.account.util.TokenGenerator
|
|||||||
import org.jetbrains.exposed.v1.core.eq
|
import org.jetbrains.exposed.v1.core.eq
|
||||||
|
|
||||||
object AccessService {
|
object AccessService {
|
||||||
fun post(principal: AuthenticationPrincipal): PostAccessResponse {
|
fun post(principal: Principal): PostAccessResponse {
|
||||||
if (principal.role != OWNER)
|
if (principal.role != OWNER)
|
||||||
throw ForbiddenException()
|
throw ForbiddenException()
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ object AccessService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getAll(principal: AuthenticationPrincipal): List<AccessResponse> {
|
fun getAll(principal: Principal): List<AccessResponse> {
|
||||||
if (principal.role != OWNER)
|
if (principal.role != OWNER)
|
||||||
throw ForbiddenException()
|
throw ForbiddenException()
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ object AccessService {
|
|||||||
.map { it.toResponse() }
|
.map { it.toResponse() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteId(principal: AuthenticationPrincipal, id: Long) {
|
fun deleteId(principal: Principal, id: Long) {
|
||||||
if (principal.role != OWNER)
|
if (principal.role != OWNER)
|
||||||
throw ForbiddenException()
|
throw ForbiddenException()
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.infendro.account.service
|
package com.infendro.account.service
|
||||||
|
|
||||||
import com.infendro.account.config.AuthenticationPrincipal
|
import com.infendro.account.config.Principal
|
||||||
import com.infendro.account.config.AuthenticationSession
|
import com.infendro.account.config.Session
|
||||||
import com.infendro.account.dto.request.*
|
import com.infendro.account.dto.request.*
|
||||||
import com.infendro.account.dto.response.*
|
import com.infendro.account.dto.response.*
|
||||||
import com.infendro.account.exception.client.ConflictException
|
import com.infendro.account.exception.client.ConflictException
|
||||||
@@ -48,7 +48,7 @@ object AccountService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getAll(principal: AuthenticationPrincipal): List<AccountResponse> {
|
fun getAll(principal: Principal): List<AccountResponse> {
|
||||||
if (principal.role != OWNER)
|
if (principal.role != OWNER)
|
||||||
throw ForbiddenException()
|
throw ForbiddenException()
|
||||||
|
|
||||||
@@ -57,18 +57,18 @@ object AccountService {
|
|||||||
.map(AccountEntity::toResponse)
|
.map(AccountEntity::toResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCurrent(principal: AuthenticationPrincipal): AccountResponse {
|
fun getCurrent(principal: Principal): AccountResponse {
|
||||||
return principal.account.toResponse()
|
return principal.account.toResponse()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteCurrent(principal: AuthenticationPrincipal) {
|
fun deleteCurrent(principal: Principal) {
|
||||||
if (principal.role == OWNER)
|
if (principal.role == OWNER)
|
||||||
throw ForbiddenException()
|
throw ForbiddenException()
|
||||||
|
|
||||||
AccountRepository.delete(principal.account)
|
AccountRepository.delete(principal.account)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun putCurrentUsername(principal: AuthenticationPrincipal, sessions: CurrentSession, request: PutAccountCurrentUsernameRequest) {
|
fun putCurrentUsername(principal: Principal, sessions: CurrentSession, request: PutAccountCurrentUsernameRequest) {
|
||||||
if (!OTP.verify(principal.account.secret, request.otp))
|
if (!OTP.verify(principal.account.secret, request.otp))
|
||||||
throw UnauthorizedException()
|
throw UnauthorizedException()
|
||||||
|
|
||||||
@@ -77,10 +77,10 @@ object AccountService {
|
|||||||
}
|
}
|
||||||
SessionRepository.delete(principal.account.sessions())
|
SessionRepository.delete(principal.account.sessions())
|
||||||
|
|
||||||
sessions.clear<AuthenticationSession>()
|
sessions.clear<Session>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun putCurrentPassword(principal: AuthenticationPrincipal, sessions: CurrentSession, request: PutAccountCurrentPasswordRequest) {
|
fun putCurrentPassword(principal: Principal, sessions: CurrentSession, request: PutAccountCurrentPasswordRequest) {
|
||||||
if (!OTP.verify(principal.account.secret, request.otp))
|
if (!OTP.verify(principal.account.secret, request.otp))
|
||||||
throw UnauthorizedException()
|
throw UnauthorizedException()
|
||||||
|
|
||||||
@@ -92,10 +92,14 @@ object AccountService {
|
|||||||
}
|
}
|
||||||
SessionRepository.delete(principal.account.sessions())
|
SessionRepository.delete(principal.account.sessions())
|
||||||
|
|
||||||
sessions.clear<AuthenticationSession>()
|
sessions.clear<Session>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun postCurrentSecret(principal: AuthenticationPrincipal, sessions: CurrentSession, request: PostAccountCurrentSecretRequest): PostAccountCurrentSecretResponse {
|
fun postCurrentSecret(
|
||||||
|
principal: Principal,
|
||||||
|
sessions: CurrentSession,
|
||||||
|
request: PostAccountCurrentSecretRequest
|
||||||
|
): PostAccountCurrentSecretResponse {
|
||||||
if (principal.account.passwordHash != PasswordHasher.hash(request.password, principal.account.passwordSalt))
|
if (principal.account.passwordHash != PasswordHasher.hash(request.password, principal.account.passwordSalt))
|
||||||
throw UnauthorizedException()
|
throw UnauthorizedException()
|
||||||
|
|
||||||
@@ -105,19 +109,19 @@ object AccountService {
|
|||||||
}
|
}
|
||||||
SessionRepository.delete(principal.account.sessions())
|
SessionRepository.delete(principal.account.sessions())
|
||||||
|
|
||||||
sessions.clear<AuthenticationSession>()
|
sessions.clear<Session>()
|
||||||
|
|
||||||
return PostAccountCurrentSecretResponse(
|
return PostAccountCurrentSecretResponse(
|
||||||
secret = secret,
|
secret = secret,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCurrentSessionAll(principal: AuthenticationPrincipal): List<SessionResponse> {
|
fun getCurrentSessionAll(principal: Principal): List<SessionResponse> {
|
||||||
return principal.account.sessions()
|
return principal.account.sessions()
|
||||||
.map(SessionEntity::toResponse)
|
.map(SessionEntity::toResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteCurrentSessionId(principal: AuthenticationPrincipal, sessions: CurrentSession, id: Long) {
|
fun deleteCurrentSessionId(principal: Principal, sessions: CurrentSession, id: Long) {
|
||||||
val session = SessionRepository
|
val session = SessionRepository
|
||||||
.singleOrNull { SessionTable.id eq id }
|
.singleOrNull { SessionTable.id eq id }
|
||||||
?: throw NotFoundException()
|
?: throw NotFoundException()
|
||||||
@@ -128,10 +132,10 @@ object AccountService {
|
|||||||
SessionRepository.delete(session)
|
SessionRepository.delete(session)
|
||||||
|
|
||||||
if (session.id == principal.session.id)
|
if (session.id == principal.session.id)
|
||||||
sessions.clear<AuthenticationSession>()
|
sessions.clear<Session>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteId(principal: AuthenticationPrincipal, id: Long) {
|
fun deleteId(principal: Principal, id: Long) {
|
||||||
val account = AccountRepository
|
val account = AccountRepository
|
||||||
.singleOrNull { AccountTable.id eq id }
|
.singleOrNull { AccountTable.id eq id }
|
||||||
?: throw NotFoundException()
|
?: throw NotFoundException()
|
||||||
@@ -142,7 +146,7 @@ object AccountService {
|
|||||||
AccountRepository.delete(account)
|
AccountRepository.delete(account)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun putIdRole(principal: AuthenticationPrincipal, id: Long, request: PutAccountIdRoleRequest) {
|
fun putIdRole(principal: Principal, id: Long, request: PutAccountIdRoleRequest) {
|
||||||
val account = AccountRepository
|
val account = AccountRepository
|
||||||
.singleOrNull { AccountTable.id eq id }
|
.singleOrNull { AccountTable.id eq id }
|
||||||
?: throw NotFoundException()
|
?: throw NotFoundException()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.infendro.account.service
|
package com.infendro.account.service
|
||||||
|
|
||||||
import com.infendro.account.config.AuthenticationPrincipal
|
import com.infendro.account.config.Principal
|
||||||
import com.infendro.account.config.AuthenticationSession
|
import com.infendro.account.config.Session
|
||||||
import com.infendro.account.dto.request.PostSessionRequest
|
import com.infendro.account.dto.request.PostSessionRequest
|
||||||
import com.infendro.account.dto.response.SessionResponse
|
import com.infendro.account.dto.response.SessionResponse
|
||||||
import com.infendro.account.dto.response.toResponse
|
import com.infendro.account.dto.response.toResponse
|
||||||
@@ -40,10 +40,10 @@ object SessionService {
|
|||||||
this.account = account
|
this.account = account
|
||||||
}
|
}
|
||||||
|
|
||||||
sessions.set(AuthenticationSession(token))
|
sessions.set(Session(token))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getAll(principal: AuthenticationPrincipal): List<SessionResponse> {
|
fun getAll(principal: Principal): List<SessionResponse> {
|
||||||
if (principal.role == USER)
|
if (principal.role == USER)
|
||||||
throw ForbiddenException()
|
throw ForbiddenException()
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ object SessionService {
|
|||||||
.map(SessionEntity::toResponse)
|
.map(SessionEntity::toResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteId(principal: AuthenticationPrincipal, id: Long) {
|
fun deleteId(principal: Principal, id: Long) {
|
||||||
if (principal.role == USER)
|
if (principal.role == USER)
|
||||||
throw ForbiddenException()
|
throw ForbiddenException()
|
||||||
|
|
||||||
@@ -67,13 +67,13 @@ object SessionService {
|
|||||||
SessionRepository.delete(session)
|
SessionRepository.delete(session)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCurrent(principal: AuthenticationPrincipal): SessionResponse {
|
fun getCurrent(principal: Principal): SessionResponse {
|
||||||
return principal.session.toResponse()
|
return principal.session.toResponse()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteCurrent(principal: AuthenticationPrincipal, sessions: CurrentSession) {
|
fun deleteCurrent(principal: Principal, sessions: CurrentSession) {
|
||||||
SessionRepository.delete(principal.session)
|
SessionRepository.delete(principal.session)
|
||||||
|
|
||||||
sessions.clear<AuthenticationSession>()
|
sessions.clear<Session>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user