make auth work
This commit is contained in:
parent
b0042d2e6b
commit
1e3d9aa1f1
9
api.http
9
api.http
@ -1,17 +1,19 @@
|
|||||||
### create row
|
### create row
|
||||||
POST http://localhost:9001/api/vehicle
|
POST http://localhost:9001/api/vehicle
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
Authorization: set-auth-token
|
||||||
|
|
||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
"number": "KA03HD6064"
|
"number": "KA01MU0556"
|
||||||
},
|
},
|
||||||
"uniqueIdentifier": "KA03HD6064"
|
"uniqueIdentifier": "KA01MU0556"
|
||||||
}
|
}
|
||||||
|
|
||||||
### create row, with autogenerated identifier
|
### create row, with autogenerated identifier
|
||||||
POST http://localhost:9001/api/log
|
POST http://localhost:9001/api/log
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
Authorization: set-auth-token
|
||||||
|
|
||||||
{
|
{
|
||||||
"data": {
|
"data": {
|
||||||
@ -26,6 +28,7 @@ GET http://localhost:9001/api/vehicle/KA03HD6064
|
|||||||
### query row
|
### query row
|
||||||
POST http://localhost:9001/api/vehicle/query
|
POST http://localhost:9001/api/vehicle/query
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
Authorization: set-auth-token
|
||||||
|
|
||||||
{
|
{
|
||||||
"sql": "select sys_pk, tenant_id, deleted_on, deleted_by, deleted, version, created_at, modified_at, created_by, modified_by, data, tags, comments, unique_identifier, entity_name from data_model where data ->> 'number' = :number",
|
"sql": "select sys_pk, tenant_id, deleted_on, deleted_by, deleted, version, created_at, modified_at, created_by, modified_by, data, tags, comments, unique_identifier, entity_name from data_model where data ->> 'number' = :number",
|
||||||
@ -37,6 +40,7 @@ Content-Type: application/json
|
|||||||
### update field
|
### update field
|
||||||
PATCH http://localhost:9001/api/vehicle/KA03HD6064
|
PATCH http://localhost:9001/api/vehicle/KA03HD6064
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
Authorization: set-auth-token
|
||||||
|
|
||||||
{
|
{
|
||||||
"key": "ownerName",
|
"key": "ownerName",
|
||||||
@ -47,6 +51,7 @@ Content-Type: application/json
|
|||||||
### upate a row
|
### upate a row
|
||||||
PUT http://localhost:9001/api/vehicle/KA03HD6064
|
PUT http://localhost:9001/api/vehicle/KA03HD6064
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
Authorization: set-auth-token
|
||||||
|
|
||||||
{
|
{
|
||||||
"number": "KA03HD6064",
|
"number": "KA03HD6064",
|
||||||
|
|||||||
@ -4,4 +4,9 @@ app.cors.hosts=www.readymixerp.com,app.readymixerp.com
|
|||||||
app.db.user=postgres
|
app.db.user=postgres
|
||||||
app.db.pass=postgres
|
app.db.pass=postgres
|
||||||
app.db.url=jdbc:postgresql://192.168.64.6/modules_app
|
app.db.url=jdbc:postgresql://192.168.64.6/modules_app
|
||||||
app.db.run_migration=true
|
app.db.run_migration=true
|
||||||
|
app.iam.url=https://auth.compegence.com
|
||||||
|
app.iam.realm=forewarn-dev
|
||||||
|
app.iam.client=forewarn
|
||||||
|
app.iam.client_redirect_uri=http://localhost:9001/auth/code
|
||||||
|
app.cache.redis_uri=redis://127.0.0.1:6379/0
|
||||||
@ -26,7 +26,9 @@ dependencies {
|
|||||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.15.+")
|
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.15.+")
|
||||||
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.15.+")
|
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.15.+")
|
||||||
|
|
||||||
|
implementation("org.bitbucket.b_c:jose4j:0.9.3")
|
||||||
implementation("org.slf4j:slf4j-simple:2.0.7")
|
implementation("org.slf4j:slf4j-simple:2.0.7")
|
||||||
|
implementation("redis.clients:jedis:5.0.2")
|
||||||
api ("net.cactusthorn.config:config-core:0.81")
|
api ("net.cactusthorn.config:config-core:0.81")
|
||||||
kapt("net.cactusthorn.config:config-compiler:0.81")
|
kapt("net.cactusthorn.config:config-compiler:0.81")
|
||||||
kapt("io.ebean:kotlin-querybean-generator:13.23.2")
|
kapt("io.ebean:kotlin-querybean-generator:13.23.2")
|
||||||
|
|||||||
@ -1,7 +1,12 @@
|
|||||||
package com.restapi
|
package com.restapi
|
||||||
|
|
||||||
|
import AuthTokenResponse
|
||||||
import com.fasterxml.jackson.databind.JsonMappingException
|
import com.fasterxml.jackson.databind.JsonMappingException
|
||||||
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
import com.restapi.config.AppConfig.Companion.appConfig
|
import com.restapi.config.AppConfig.Companion.appConfig
|
||||||
|
import com.restapi.config.Auth
|
||||||
|
import com.restapi.config.Auth.getAuthEndpoint
|
||||||
|
import com.restapi.config.AuthEndpoint
|
||||||
import com.restapi.domain.DataModel
|
import com.restapi.domain.DataModel
|
||||||
import com.restapi.domain.DataNotFoundException
|
import com.restapi.domain.DataNotFoundException
|
||||||
import com.restapi.domain.Session
|
import com.restapi.domain.Session
|
||||||
@ -9,6 +14,9 @@ import com.restapi.domain.Session.creatSeq
|
|||||||
import com.restapi.domain.Session.database
|
import com.restapi.domain.Session.database
|
||||||
import com.restapi.domain.Session.findByEntityAndId
|
import com.restapi.domain.Session.findByEntityAndId
|
||||||
import com.restapi.domain.Session.nextUniqId
|
import com.restapi.domain.Session.nextUniqId
|
||||||
|
import com.restapi.domain.Session.objectMapper
|
||||||
|
import com.restapi.domain.Session.redis
|
||||||
|
import com.restapi.domain.Session.setAuthorizedUser
|
||||||
import io.ebean.CallableSql
|
import io.ebean.CallableSql
|
||||||
import io.ebean.DuplicateKeyException
|
import io.ebean.DuplicateKeyException
|
||||||
import io.ebean.RawSqlBuilder
|
import io.ebean.RawSqlBuilder
|
||||||
@ -17,10 +25,18 @@ import io.javalin.apibuilder.ApiBuilder.*
|
|||||||
import io.javalin.http.*
|
import io.javalin.http.*
|
||||||
import io.javalin.json.JavalinJackson
|
import io.javalin.json.JavalinJackson
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
import java.net.URI
|
||||||
|
import java.net.URLEncoder
|
||||||
|
import java.net.http.HttpClient
|
||||||
|
import java.net.http.HttpRequest
|
||||||
|
import java.net.http.HttpRequest.BodyPublishers
|
||||||
|
import java.net.http.HttpResponse.BodyHandlers
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
val logger = LoggerFactory.getLogger("api")
|
val logger = LoggerFactory.getLogger("api")
|
||||||
|
|
||||||
Javalin
|
Javalin
|
||||||
.create { cfg ->
|
.create { cfg ->
|
||||||
cfg.http.generateEtags = true
|
cfg.http.generateEtags = true
|
||||||
@ -39,7 +55,47 @@ fun main(args: Array<String>) {
|
|||||||
cfg.jsonMapper(JavalinJackson(Session.objectMapper))
|
cfg.jsonMapper(JavalinJackson(Session.objectMapper))
|
||||||
}
|
}
|
||||||
.routes {
|
.routes {
|
||||||
before("/*") { ctx ->
|
|
||||||
|
path("/auth") {
|
||||||
|
get("/init") {
|
||||||
|
val endpoint = getAuthEndpoint().authorizationEndpoint
|
||||||
|
|
||||||
|
val redirectUrl =
|
||||||
|
"$endpoint?response_type=code&client_id=${appConfig.iamClient()}&redirect_uri=${appConfig.iamClientRedirectUri()}&scope=profile&state=1234zyx"
|
||||||
|
it.redirect(redirectUrl)
|
||||||
|
}
|
||||||
|
get("/code") {
|
||||||
|
|
||||||
|
val code = it.queryParam("code") ?: throw BadRequestResponse("not proper")
|
||||||
|
|
||||||
|
val ep = getAuthEndpoint().tokenEndpoint
|
||||||
|
val client = HttpClient.newHttpClient()
|
||||||
|
val req = HttpRequest.newBuilder()
|
||||||
|
.uri(URI.create(ep))
|
||||||
|
.POST(
|
||||||
|
BodyPublishers.ofString(
|
||||||
|
getFormDataAsString(
|
||||||
|
mapOf(
|
||||||
|
"code" to code,
|
||||||
|
"redirect_uri" to appConfig.iamClientRedirectUri(),
|
||||||
|
"client_id" to appConfig.iamClient(),
|
||||||
|
"grant_type" to "authorization_code",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
.build()
|
||||||
|
val message = client.send(req, BodyHandlers.ofString()).body()
|
||||||
|
val atResponse = objectMapper.readValue<AuthTokenResponse>(message)
|
||||||
|
|
||||||
|
//lets keep auth token refreshed
|
||||||
|
redis.sadd("AUTH_TOKEN", message)
|
||||||
|
it.result(atResponse.accessToken).contentType(ContentType.TEXT_PLAIN)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
before("/api/*") { ctx ->
|
||||||
//validate, auth token
|
//validate, auth token
|
||||||
|
|
||||||
//allow only alpha, numeric, hypen, underscore, dot in paths
|
//allow only alpha, numeric, hypen, underscore, dot in paths
|
||||||
@ -51,6 +107,12 @@ fun main(args: Array<String>) {
|
|||||||
throw IllegalArgumentException()
|
throw IllegalArgumentException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val at = ctx.header("Authorization")?.replace("Bearer ", "")?.replace("Bearer: ", "")?.trim()
|
||||||
|
?: throw UnauthorizedResponse()
|
||||||
|
val pt = Auth.parseAuthToken(authToken = at)
|
||||||
|
|
||||||
|
setAuthorizedUser(pt)
|
||||||
}
|
}
|
||||||
path("/api") {
|
path("/api") {
|
||||||
post("/execute/{name}") {
|
post("/execute/{name}") {
|
||||||
@ -174,4 +236,17 @@ data class Query(
|
|||||||
val params: Map<String, Any>
|
val params: Map<String, Any>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private fun getFormDataAsString(formData: Map<String, String>): String {
|
||||||
|
val formBodyBuilder = StringBuilder()
|
||||||
|
for ((key, value) in formData) {
|
||||||
|
if (formBodyBuilder.length > 0) {
|
||||||
|
formBodyBuilder.append("&")
|
||||||
|
}
|
||||||
|
formBodyBuilder.append(URLEncoder.encode(key, StandardCharsets.UTF_8))
|
||||||
|
formBodyBuilder.append("=")
|
||||||
|
formBodyBuilder.append(URLEncoder.encode(value, StandardCharsets.UTF_8))
|
||||||
|
}
|
||||||
|
return formBodyBuilder.toString()
|
||||||
|
}
|
||||||
|
|
||||||
data class PatchValue(val key: String, val value: Any)
|
data class PatchValue(val key: String, val value: Any)
|
||||||
@ -5,6 +5,7 @@ import net.cactusthorn.config.core.Default
|
|||||||
import net.cactusthorn.config.core.Key
|
import net.cactusthorn.config.core.Key
|
||||||
import net.cactusthorn.config.core.factory.ConfigFactory
|
import net.cactusthorn.config.core.factory.ConfigFactory
|
||||||
import net.cactusthorn.config.core.loader.LoadStrategy
|
import net.cactusthorn.config.core.loader.LoadStrategy
|
||||||
|
import java.util.Optional
|
||||||
|
|
||||||
const val INITIAL_ROLES_JSON = """{
|
const val INITIAL_ROLES_JSON = """{
|
||||||
"roles": []
|
"roles": []
|
||||||
@ -41,6 +42,26 @@ interface AppConfig {
|
|||||||
@Key("app.db.run_migration")
|
@Key("app.db.run_migration")
|
||||||
fun dbRunMigration(): Boolean
|
fun dbRunMigration(): Boolean
|
||||||
|
|
||||||
|
@Key("app.iam.url")
|
||||||
|
fun iamUrl(): String
|
||||||
|
|
||||||
|
@Key("app.iam.realm")
|
||||||
|
fun iamRealm(): String
|
||||||
|
|
||||||
|
@Key("app.iam.client")
|
||||||
|
fun iamClient(): String
|
||||||
|
|
||||||
|
@Key("app.iam.client_redirect_uri")
|
||||||
|
fun iamClientRedirectUri(): String
|
||||||
|
|
||||||
|
@Key("app.iam.client_id")
|
||||||
|
fun iamClientId(): Optional<String>
|
||||||
|
|
||||||
|
@Key("app.iam.client_secret")
|
||||||
|
fun iamClientSecret(): Optional<String>
|
||||||
|
|
||||||
|
@Key("app.cache.redis_uri")
|
||||||
|
fun redisUri(): Optional<String>
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val appConfig: AppConfig = ConfigFactory.builder().build().create(AppConfig::class.java)
|
val appConfig: AppConfig = ConfigFactory.builder().build().create(AppConfig::class.java)
|
||||||
|
|||||||
72
src/main/kotlin/com/restapi/config/Auth.kt
Normal file
72
src/main/kotlin/com/restapi/config/Auth.kt
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package com.restapi.config
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
|
import com.restapi.config.AppConfig.Companion.appConfig
|
||||||
|
import com.restapi.domain.Session
|
||||||
|
import com.restapi.domain.Session.objectMapper
|
||||||
|
import io.javalin.http.Context
|
||||||
|
import io.javalin.http.HandlerType
|
||||||
|
import io.javalin.http.UnauthorizedResponse
|
||||||
|
import org.jose4j.jwk.HttpsJwks
|
||||||
|
import org.jose4j.jwt.consumer.ErrorCodes
|
||||||
|
import org.jose4j.jwt.consumer.InvalidJwtException
|
||||||
|
import org.jose4j.jwt.consumer.JwtConsumerBuilder
|
||||||
|
import org.jose4j.keys.resolvers.HttpsJwksVerificationKeyResolver
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import java.net.URI
|
||||||
|
import java.net.http.HttpClient
|
||||||
|
import java.net.http.HttpRequest
|
||||||
|
import java.net.http.HttpResponse
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
import java.util.function.Function
|
||||||
|
|
||||||
|
object Auth {
|
||||||
|
|
||||||
|
|
||||||
|
private val authCache = ConcurrentHashMap<String, AuthEndpoint>()
|
||||||
|
|
||||||
|
fun getAuthEndpoint(): AuthEndpoint {
|
||||||
|
return authCache.computeIfAbsent("AUTH") {
|
||||||
|
val wellKnown =
|
||||||
|
"${appConfig.iamUrl()}/realms/${appConfig.iamRealm()}/.well-known/openid-configuration"
|
||||||
|
val client = HttpClient.newHttpClient()
|
||||||
|
|
||||||
|
val req = HttpRequest.newBuilder()
|
||||||
|
.uri(URI.create(wellKnown))
|
||||||
|
.GET().build()
|
||||||
|
|
||||||
|
objectMapper.readValue<AuthEndpoint>(
|
||||||
|
client.send(req, HttpResponse.BodyHandlers.ofString()).body()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private val jwtConsumer = JwtConsumerBuilder()
|
||||||
|
.setRequireExpirationTime()
|
||||||
|
.setAllowedClockSkewInSeconds(30)
|
||||||
|
.setRequireSubject()
|
||||||
|
.setExpectedIssuer(getAuthEndpoint().issuer)
|
||||||
|
.setExpectedAudience("account")
|
||||||
|
.setVerificationKeyResolver(HttpsJwksVerificationKeyResolver(HttpsJwks(getAuthEndpoint().jwksUri)))
|
||||||
|
.build()
|
||||||
|
|
||||||
|
|
||||||
|
fun parseAuthToken(authToken: String): AuthUser {
|
||||||
|
|
||||||
|
// Validate the JWT and process it to the Claims
|
||||||
|
val jwtClaims = jwtConsumer.process(authToken)
|
||||||
|
val userId = jwtClaims.jwtClaims.claimsMap["preferred_username"] as String
|
||||||
|
val tenant = jwtClaims.jwtClaims.claimsMap["tenant"] as String
|
||||||
|
val roles = ((jwtClaims.jwtClaims.claimsMap["realm_access"] as Map<String, Any>)["roles"]) as List<String>
|
||||||
|
|
||||||
|
return AuthUser(
|
||||||
|
userName = userId,
|
||||||
|
tenant = tenant,
|
||||||
|
roles = roles
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
data class AuthUser(val userName: String, val tenant: String, val roles: List<String>)
|
||||||
132
src/main/kotlin/com/restapi/config/AuthEndpoint.kt
Normal file
132
src/main/kotlin/com/restapi/config/AuthEndpoint.kt
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
package com.restapi.config
|
||||||
|
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
|
|
||||||
|
data class AuthEndpoint(
|
||||||
|
@JsonProperty("acr_values_supported")
|
||||||
|
val acrValuesSupported: List<String>,
|
||||||
|
@JsonProperty("authorization_encryption_alg_values_supported")
|
||||||
|
val authorizationEncryptionAlgValuesSupported: List<String>,
|
||||||
|
@JsonProperty("authorization_encryption_enc_values_supported")
|
||||||
|
val authorizationEncryptionEncValuesSupported: List<String>,
|
||||||
|
@JsonProperty("authorization_endpoint")
|
||||||
|
val authorizationEndpoint: String,
|
||||||
|
@JsonProperty("authorization_signing_alg_values_supported")
|
||||||
|
val authorizationSigningAlgValuesSupported: List<String>,
|
||||||
|
@JsonProperty("backchannel_authentication_endpoint")
|
||||||
|
val backchannelAuthenticationEndpoint: String,
|
||||||
|
@JsonProperty("backchannel_authentication_request_signing_alg_values_supported")
|
||||||
|
val backchannelAuthenticationRequestSigningAlgValuesSupported: List<String>,
|
||||||
|
@JsonProperty("backchannel_logout_session_supported")
|
||||||
|
val backchannelLogoutSessionSupported: Boolean,
|
||||||
|
@JsonProperty("backchannel_logout_supported")
|
||||||
|
val backchannelLogoutSupported: Boolean,
|
||||||
|
@JsonProperty("backchannel_token_delivery_modes_supported")
|
||||||
|
val backchannelTokenDeliveryModesSupported: List<String>,
|
||||||
|
@JsonProperty("check_session_iframe")
|
||||||
|
val checkSessionIframe: String,
|
||||||
|
@JsonProperty("claim_types_supported")
|
||||||
|
val claimTypesSupported: List<String>,
|
||||||
|
@JsonProperty("claims_parameter_supported")
|
||||||
|
val claimsParameterSupported: Boolean,
|
||||||
|
@JsonProperty("claims_supported")
|
||||||
|
val claimsSupported: List<String>,
|
||||||
|
@JsonProperty("code_challenge_methods_supported")
|
||||||
|
val codeChallengeMethodsSupported: List<String>,
|
||||||
|
@JsonProperty("device_authorization_endpoint")
|
||||||
|
val deviceAuthorizationEndpoint: String,
|
||||||
|
@JsonProperty("end_session_endpoint")
|
||||||
|
val endSessionEndpoint: String,
|
||||||
|
@JsonProperty("frontchannel_logout_session_supported")
|
||||||
|
val frontchannelLogoutSessionSupported: Boolean,
|
||||||
|
@JsonProperty("frontchannel_logout_supported")
|
||||||
|
val frontchannelLogoutSupported: Boolean,
|
||||||
|
@JsonProperty("grant_types_supported")
|
||||||
|
val grantTypesSupported: List<String>,
|
||||||
|
@JsonProperty("id_token_encryption_alg_values_supported")
|
||||||
|
val idTokenEncryptionAlgValuesSupported: List<String>,
|
||||||
|
@JsonProperty("id_token_encryption_enc_values_supported")
|
||||||
|
val idTokenEncryptionEncValuesSupported: List<String>,
|
||||||
|
@JsonProperty("id_token_signing_alg_values_supported")
|
||||||
|
val idTokenSigningAlgValuesSupported: List<String>,
|
||||||
|
@JsonProperty("introspection_endpoint")
|
||||||
|
val introspectionEndpoint: String,
|
||||||
|
@JsonProperty("introspection_endpoint_auth_methods_supported")
|
||||||
|
val introspectionEndpointAuthMethodsSupported: List<String>,
|
||||||
|
@JsonProperty("introspection_endpoint_auth_signing_alg_values_supported")
|
||||||
|
val introspectionEndpointAuthSigningAlgValuesSupported: List<String>,
|
||||||
|
@JsonProperty("issuer")
|
||||||
|
val issuer: String,
|
||||||
|
@JsonProperty("jwks_uri")
|
||||||
|
val jwksUri: String,
|
||||||
|
@JsonProperty("mtls_endpoint_aliases")
|
||||||
|
val mtlsEndpointAliases: MtlsEndpointAliases,
|
||||||
|
@JsonProperty("pushed_authorization_request_endpoint")
|
||||||
|
val pushedAuthorizationRequestEndpoint: String,
|
||||||
|
@JsonProperty("registration_endpoint")
|
||||||
|
val registrationEndpoint: String,
|
||||||
|
@JsonProperty("request_object_encryption_alg_values_supported")
|
||||||
|
val requestObjectEncryptionAlgValuesSupported: List<String>,
|
||||||
|
@JsonProperty("request_object_encryption_enc_values_supported")
|
||||||
|
val requestObjectEncryptionEncValuesSupported: List<String>,
|
||||||
|
@JsonProperty("request_object_signing_alg_values_supported")
|
||||||
|
val requestObjectSigningAlgValuesSupported: List<String>,
|
||||||
|
@JsonProperty("request_parameter_supported")
|
||||||
|
val requestParameterSupported: Boolean,
|
||||||
|
@JsonProperty("request_uri_parameter_supported")
|
||||||
|
val requestUriParameterSupported: Boolean,
|
||||||
|
@JsonProperty("require_pushed_authorization_requests")
|
||||||
|
val requirePushedAuthorizationRequests: Boolean,
|
||||||
|
@JsonProperty("require_request_uri_registration")
|
||||||
|
val requireRequestUriRegistration: Boolean,
|
||||||
|
@JsonProperty("response_modes_supported")
|
||||||
|
val responseModesSupported: List<String>,
|
||||||
|
@JsonProperty("response_types_supported")
|
||||||
|
val responseTypesSupported: List<String>,
|
||||||
|
@JsonProperty("revocation_endpoint")
|
||||||
|
val revocationEndpoint: String,
|
||||||
|
@JsonProperty("revocation_endpoint_auth_methods_supported")
|
||||||
|
val revocationEndpointAuthMethodsSupported: List<String>,
|
||||||
|
@JsonProperty("revocation_endpoint_auth_signing_alg_values_supported")
|
||||||
|
val revocationEndpointAuthSigningAlgValuesSupported: List<String>,
|
||||||
|
@JsonProperty("scopes_supported")
|
||||||
|
val scopesSupported: List<String>,
|
||||||
|
@JsonProperty("subject_types_supported")
|
||||||
|
val subjectTypesSupported: List<String>,
|
||||||
|
@JsonProperty("tls_client_certificate_bound_access_tokens")
|
||||||
|
val tlsClientCertificateBoundAccessTokens: Boolean,
|
||||||
|
@JsonProperty("token_endpoint")
|
||||||
|
val tokenEndpoint: String,
|
||||||
|
@JsonProperty("token_endpoint_auth_methods_supported")
|
||||||
|
val tokenEndpointAuthMethodsSupported: List<String>,
|
||||||
|
@JsonProperty("token_endpoint_auth_signing_alg_values_supported")
|
||||||
|
val tokenEndpointAuthSigningAlgValuesSupported: List<String>,
|
||||||
|
@JsonProperty("userinfo_encryption_alg_values_supported")
|
||||||
|
val userinfoEncryptionAlgValuesSupported: List<String>,
|
||||||
|
@JsonProperty("userinfo_encryption_enc_values_supported")
|
||||||
|
val userinfoEncryptionEncValuesSupported: List<String>,
|
||||||
|
@JsonProperty("userinfo_endpoint")
|
||||||
|
val userinfoEndpoint: String,
|
||||||
|
@JsonProperty("userinfo_signing_alg_values_supported")
|
||||||
|
val userinfoSigningAlgValuesSupported: List<String>
|
||||||
|
) {
|
||||||
|
data class MtlsEndpointAliases(
|
||||||
|
@JsonProperty("backchannel_authentication_endpoint")
|
||||||
|
val backchannelAuthenticationEndpoint: String,
|
||||||
|
@JsonProperty("device_authorization_endpoint")
|
||||||
|
val deviceAuthorizationEndpoint: String,
|
||||||
|
@JsonProperty("introspection_endpoint")
|
||||||
|
val introspectionEndpoint: String,
|
||||||
|
@JsonProperty("pushed_authorization_request_endpoint")
|
||||||
|
val pushedAuthorizationRequestEndpoint: String,
|
||||||
|
@JsonProperty("registration_endpoint")
|
||||||
|
val registrationEndpoint: String,
|
||||||
|
@JsonProperty("revocation_endpoint")
|
||||||
|
val revocationEndpoint: String,
|
||||||
|
@JsonProperty("token_endpoint")
|
||||||
|
val tokenEndpoint: String,
|
||||||
|
@JsonProperty("userinfo_endpoint")
|
||||||
|
val userinfoEndpoint: String
|
||||||
|
)
|
||||||
|
}
|
||||||
23
src/main/kotlin/com/restapi/config/AuthTokenResponse.kt
Normal file
23
src/main/kotlin/com/restapi/config/AuthTokenResponse.kt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
|
||||||
|
data class AuthTokenResponse(
|
||||||
|
@JsonProperty("access_token")
|
||||||
|
val accessToken: String,
|
||||||
|
@JsonProperty("expires_in")
|
||||||
|
val expiresIn: Int,
|
||||||
|
@JsonProperty("not-before-policy")
|
||||||
|
val notBeforePolicy: Int,
|
||||||
|
@JsonProperty("refresh_expires_in")
|
||||||
|
val refreshExpiresIn: Int,
|
||||||
|
@JsonProperty("refresh_token")
|
||||||
|
val refreshToken: String,
|
||||||
|
@JsonProperty("scope")
|
||||||
|
val scope: String,
|
||||||
|
@JsonProperty("session_state")
|
||||||
|
val sessionState: String,
|
||||||
|
@JsonProperty("token_type")
|
||||||
|
val tokenType: String,
|
||||||
|
val createdAt: LocalDateTime = LocalDateTime.now()
|
||||||
|
)
|
||||||
@ -6,27 +6,26 @@ import com.fasterxml.jackson.databind.SerializationFeature
|
|||||||
import com.fasterxml.jackson.databind.module.SimpleModule
|
import com.fasterxml.jackson.databind.module.SimpleModule
|
||||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||||
import com.restapi.config.AppConfig.Companion.appConfig
|
import com.restapi.config.AppConfig.Companion.appConfig
|
||||||
|
import com.restapi.config.AuthUser
|
||||||
import io.ebean.Database
|
import io.ebean.Database
|
||||||
import io.ebean.DatabaseFactory
|
import io.ebean.DatabaseFactory
|
||||||
import io.ebean.config.CurrentTenantProvider
|
import io.ebean.config.CurrentTenantProvider
|
||||||
import io.ebean.config.CurrentUserProvider
|
import io.ebean.config.CurrentUserProvider
|
||||||
import io.ebean.config.DatabaseConfig
|
import io.ebean.config.DatabaseConfig
|
||||||
import io.ebean.config.TenantMode
|
import io.ebean.config.TenantMode
|
||||||
|
import redis.clients.jedis.JedisPooled
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.jvm.optionals.getOrDefault
|
||||||
data class CurrentUser(
|
|
||||||
val anon: Boolean = true,
|
|
||||||
val userId: String = "",
|
|
||||||
val tenantId: String = ""
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
object Session {
|
object Session {
|
||||||
private val currentUser = object : ThreadLocal<CurrentUser>() {
|
private val currentUser = object : ThreadLocal<AuthUser>() {
|
||||||
override fun initialValue(): CurrentUser {
|
override fun initialValue(): AuthUser {
|
||||||
return CurrentUser()
|
return AuthUser("", "", emptyList<String>())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fun setAuthorizedUser(a: AuthUser) = currentUser.set(a)
|
||||||
|
|
||||||
private val sc = DatabaseConfig().apply {
|
private val sc = DatabaseConfig().apply {
|
||||||
loadFromProperties(Properties().apply {
|
loadFromProperties(Properties().apply {
|
||||||
setProperty("datasource.db.username", appConfig.dbUser())
|
setProperty("datasource.db.username", appConfig.dbUser())
|
||||||
@ -35,8 +34,8 @@ object Session {
|
|||||||
setProperty("ebean.migration.run", appConfig.dbRunMigration().toString())
|
setProperty("ebean.migration.run", appConfig.dbRunMigration().toString())
|
||||||
})
|
})
|
||||||
tenantMode = TenantMode.PARTITION
|
tenantMode = TenantMode.PARTITION
|
||||||
currentTenantProvider = CurrentTenantProvider { currentUser.get().tenantId }
|
currentTenantProvider = CurrentTenantProvider { currentUser.get().tenant }
|
||||||
currentUserProvider = CurrentUserProvider { currentUser.get().userId }
|
currentUserProvider = CurrentUserProvider { currentUser.get().userName }
|
||||||
}
|
}
|
||||||
|
|
||||||
val database: Database = DatabaseFactory.create(sc)
|
val database: Database = DatabaseFactory.create(sc)
|
||||||
@ -46,7 +45,7 @@ object Session {
|
|||||||
findAndRegisterModules()
|
findAndRegisterModules()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun currentUser() = currentUser.get().userId
|
fun currentUser() = currentUser.get().userName
|
||||||
|
|
||||||
fun Database.findByEntityAndId(entity: String, id: String): DataModel {
|
fun Database.findByEntityAndId(entity: String, id: String): DataModel {
|
||||||
return find(DataModel::class.java)
|
return find(DataModel::class.java)
|
||||||
@ -68,6 +67,8 @@ object Session {
|
|||||||
return String.format("%s-%s", entity, "$s".padStart(10, '0'))
|
return String.format("%s-%s", entity, "$s".padStart(10, '0'))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val redis = JedisPooled(appConfig.redisUri().getOrDefault("redis://localhost:6739/0"))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object DataNotFoundException : Exception() {
|
object DataNotFoundException : Exception() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user