Skip to content

Commit

Permalink
feat : Update oauth service
Browse files Browse the repository at this point in the history
  • Loading branch information
TrulyNotMalware committed Jan 24, 2024
1 parent 8142a10 commit d5d3e7e
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 11 deletions.
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ java.sourceCompatibility = JavaVersion.VERSION_21
val mockkVersion = "1.13.8"
val kotestVersion = "5.7.2"
val kotestSpringExtensionVersion = "1.1.3"

allprojects{
group = "dev.notypie"
version = "0.0.1-SNAPSHOT"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
package dev.notypie.application

class JpaOAuth2AuthorizationService {
import com.fasterxml.jackson.databind.ObjectMapper
import dev.notypie.jpa.dao.AuthorizationRepository
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository

class JpaOAuth2AuthorizationService(
private val authorizationRepository: AuthorizationRepository,
private val registeredClientRepository: RegisteredClientRepository,
private val objectMapper: ObjectMapper
){
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package dev.notypie.common.utils

import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm
import org.springframework.security.oauth2.server.authorization.settings.ConfigurationSettingNames
import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings
import org.springframework.util.Assert
import java.lang.Boolean
import java.time.Duration
import java.util.*
import kotlin.Any
import kotlin.Double
import kotlin.IllegalArgumentException
import kotlin.String


class TokenSettingsSerializer {
private val tokenSettings: TokenSettings

constructor(tokenSettings: TokenSettings){
this.tokenSettings = this.buildTokenSettings(tokenSettings.settings)
}

constructor(setting: Map<String, String>){
this.tokenSettings = this.buildTokenSettings(setting)
}
/**
* Fixed an issue that did not serialize correctly when reading values from a database.
* 1. [Double][java.lang.Double] type to [Duration][java.time.Duration]
* 2. [Map][java.util.Map] type to [OAuth2TokenFormat][org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat] instance.
* @param settings the [Map][java.util.Map] object from database.
* @return [TokenSettings][org.springframework.security.oauth2.server.authorization.settings.TokenSettings] object.
*/
private fun buildTokenSettings(settings: Map<String, Any>): TokenSettings {
return TokenSettings.builder() //Convert Duration type.
.authorizationCodeTimeToLive(
this.durationConverter(getSetting(ConfigurationSettingNames.Token.AUTHORIZATION_CODE_TIME_TO_LIVE,settings))
)
.accessTokenTimeToLive(
this.durationConverter(getSetting(ConfigurationSettingNames.Token.ACCESS_TOKEN_TIME_TO_LIVE, settings))
)
.deviceCodeTimeToLive(
this.durationConverter(getSetting(ConfigurationSettingNames.Token.DEVICE_CODE_TIME_TO_LIVE, settings))
)
.refreshTokenTimeToLive(
this.durationConverter(getSetting(ConfigurationSettingNames.Token.REFRESH_TOKEN_TIME_TO_LIVE, settings))
) //Others
.reuseRefreshTokens(
Boolean.TRUE == getSetting<Any>(ConfigurationSettingNames.Token.REUSE_REFRESH_TOKENS, settings)
)
.idTokenSignatureAlgorithm(
SignatureAlgorithm.from(
getSetting(
ConfigurationSettingNames.Token.ID_TOKEN_SIGNATURE_ALGORITHM,
settings
)
)
)
.accessTokenFormat(
this.tokenFormatConverter(
getSetting(ConfigurationSettingNames.Token.ACCESS_TOKEN_FORMAT, settings),
null
)
)
.build()
}

/**
* Convert double value to Duration type.
* change Double value to Duration of seconds.
* @param value
* The [Double][java.lang.Double] value.
* @return [duration][java.time.Duration] instance.
*/
private fun durationConverter(value: Double): Duration = Duration.ofSeconds(Math.round(value))


/**
* Cast the [Map][java.util.Map] instance to [OAuth2TokenFormat][org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat] object.
* this function throws [IllegalArgumentException][java.lang.IllegalArgumentException] when cannot type cast.
* @param map the data object
* @param keyName Nullable string key name. the default key name is "value", but you could also change this.
* @see IllegalArgumentException
*
* @return [OAuth2TokenFormat][org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat] instance.
*/
private fun tokenFormatConverter(map: Map<String, Any>, keyName: String?): OAuth2TokenFormat {
//in my case, value from database is LinkedHashMap.
Assert.notEmpty(map, "Map object is empty.")
val key: String = keyName ?: "value"
if (OAuth2TokenFormat.SELF_CONTAINED.value == getSetting(key, map)) return OAuth2TokenFormat.SELF_CONTAINED
else if (OAuth2TokenFormat.REFERENCE.value == getSetting(key, map)) return OAuth2TokenFormat.REFERENCE
throw IllegalArgumentException("Cannot convert " + getSetting(key, map) + "to OAuth2TokenFormat.")
}

/**
* get value from Map object. this function throws IllegalArgumentException.
* @see IllegalArgumentException
*
* @param name The key name for extract from map.
* @param settings the Map object.
* @param <T> Return type.
</T> */
private fun <T> getSetting(name: String, settings: Map<String, Any>): T {
Assert.hasText(name, "name cannot be empty")
Assert.notEmpty(settings, "Map object is empty.")
Assert.notNull(settings[name], "Value not exist.")
return settings[name] as T
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package dev.notypie.configurations

import dev.notypie.jwt.dto.LoginRequestDto
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.springframework.context.annotation.Profile
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.Authentication
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import java.io.BufferedReader
import java.io.InputStream
import java.io.InputStreamReader

@Profile("jwt")
class AuthenticationFilter(
private val authenticationManager: AuthenticationManager
): UsernamePasswordAuthenticationFilter() {

override fun attemptAuthentication(request: HttpServletRequest, response: HttpServletResponse): Authentication {

val builder: StringBuilder = StringBuilder()
val inputStream: InputStream = request.inputStream

val bufferedReader = BufferedReader(InputStreamReader(inputStream))
while( true ){
val line: String = bufferedReader.readLine() ?: break
builder.append(line)
}
//FIXME LATER
val list = builder.toString().split("&")
val userIdList = list[0].split("=")
val passwordList = list[1].split("=")

return this.authenticationManager.authenticate(
UsernamePasswordAuthenticationToken(userIdList[1], passwordList[1])
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package dev.notypie.jpa.dao

import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import dev.notypie.domain.Client
import org.springframework.security.jackson2.SecurityJackson2Modules
import org.springframework.security.oauth2.core.AuthorizationGrantType
import org.springframework.security.oauth2.core.ClientAuthenticationMethod
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository
import org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationServerJackson2Module
import org.springframework.stereotype.Service
import org.springframework.util.StringUtils

@Service
class JpaRegisteredClientRepository(
Expand Down Expand Up @@ -48,26 +50,36 @@ class JpaRegisteredClientRepository(
}
}
override fun save(registeredClient: RegisteredClient) {
TODO("Not yet implemented")
this.clientRepository.save(this.toEntity(registeredClient))
}

override fun findById(id: String): RegisteredClient {
TODO("Not yet implemented")
// if(id.isBlank()) throw IllegalArgumentException("id cannot be empty")
// return this.clientRepository.findById(id).filter { it }
}

override fun findByClientId(clientId: String): RegisteredClient {
TODO("Not yet implemented")
}

// private fun toEntity(registeredClient: RegisteredClient): Client {
// val clientAuthenticationMethods: MutableList<String> = mutableListOf()
// registeredClient.clientAuthenticationMethods.forEach{ clientAuthenticationMethods.add(it.value) }
// val authorizationGrantType: MutableList<String> = mutableListOf()
// registeredClient.authorizationGrantTypes.forEach { authorizationGrantType.add(it.value) }
// return Client(id = registeredClient.id.toLong(),
// clientId = registeredClient.clientId, clientIdIssuedAt = registeredClient.clientIdIssuedAt,
// clientSecret = registeredClient.clientSecret)
// }
private fun toObject(client: Client): RegisteredClient{
TODO("Not yet implemented")
}

private fun toEntity(registeredClient: RegisteredClient): Client
= Client(id = registeredClient.id.toLong(), clientId = registeredClient.clientId,
clientIdIssuedAt = registeredClient.clientIdIssuedAt!!, clientSecret = registeredClient.clientSecret!!,
clientSecretExpiresAt = registeredClient.clientSecretExpiresAt!!, clientName = registeredClient.clientName,
clientAuthenticationMethods = StringUtils.collectionToCommaDelimitedString(registeredClient.clientAuthenticationMethods.map { it.value }),
authorizationGrantTypes = StringUtils.collectionToCommaDelimitedString(registeredClient.authorizationGrantTypes.map { it.value }),
redirectUris = StringUtils.collectionToCommaDelimitedString(registeredClient.redirectUris),
postLogoutRedirectUris = StringUtils.collectionToCommaDelimitedString(registeredClient.postLogoutRedirectUris),
scopes = StringUtils.collectionToCommaDelimitedString(registeredClient.scopes),
clientSettings = this.writeMap(registeredClient.clientSettings.settings),
tokenSettings = this.writeMap(registeredClient.tokenSettings.settings)
)


private fun parseMap(data: String): Map<String, Any> {
try {
Expand Down

0 comments on commit d5d3e7e

Please sign in to comment.