Problem using Spring OAuth in standard Java8 environment
My sample app is running on-premises. But it doesn't work in standard Java8 environment. The following project is a sample application project.
https://github.com/nosix/appengine-java8-spring-oauth2
In Java8 standard environment, the following error appears:
Authentication Failed: Could not obtain access token
I added logs to the Spring OAuth source code and investigated the reason. The reason for the error is that session data has been lost.
It worked like this:
preservedState
is null in AuthorizationCodeAccessTokenProvider::getParametersForTokenRequest
. Thus, it is InvalidRequestException
thrown away. This is the cause of the error.
setPreservedState
the method is called in OAuth2RestTemplate::acquireAccessToken
. It is preservedState
set to null at this time .
DefaultOAuth2ClientContext
copy has preservedState
. preservedState
instance DefaultOAuth2ClientContext
is null in standard Java8 environment. But in the local environment it is not null.
DefaultOAuth2ClientContext
is saved in the session. I understand that it is stored in memory in the local environment and in the data store in the standard environment.
From the above, I guessed that the session data was lost.
I'm stuck investigating. Is there information that serves as a clue to a solution?
source to share
I had the same problem. Finally, I executed a custom SessionRepository
Spring session like this: ( see also this commit )
Repository class:
class MemcacheSessionRepository(private val memcacheService: MemcacheService) : SessionRepository<MemcacheSession> {
private val log = LoggerFactory.getLogger(javaClass)
private val maxInactiveIntervalInSeconds: Int = 3600
override fun createSession() = MemcacheSession().also { session ->
session.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds
log.debug("createSession() = {}", session.id)
}
override fun save(session: MemcacheSession) {
log.debug("save({}) with expiration {}", session.id, session.maxInactiveIntervalInSeconds)
memcacheService.put(session.id, session, Expiration.byDeltaSeconds(session.maxInactiveIntervalInSeconds))
}
override fun getSession(id: String): MemcacheSession? =
(memcacheService.get(id) as? MemcacheSession)?.also { session ->
session.setLastAccessedTimeToNow()
}.also { session ->
log.debug("getSession({}) = {}", id, session?.id)
}
override fun delete(id: String) {
log.debug("delete({})", id)
memcacheService.delete(id)
}
}
Entity class:
class MemcacheSession : ExpiringSession, Serializable {
companion object {
const val serialVersionUID: Long = 1
}
private val id: String = UUID.randomUUID().toString()
private val creationTime: Long = System.currentTimeMillis()
private var lastAccessedTime: Long = creationTime
private var maxInactiveIntervalInSeconds: Int = 3600
private val attributes: MutableMap<String, Any> = mutableMapOf()
override fun getId() = id
override fun getCreationTime() = creationTime
override fun getLastAccessedTime() = lastAccessedTime
override fun setLastAccessedTime(time: Long) {
lastAccessedTime = time
}
fun setLastAccessedTimeToNow() {
lastAccessedTime = System.currentTimeMillis()
}
override fun getMaxInactiveIntervalInSeconds() = maxInactiveIntervalInSeconds
override fun setMaxInactiveIntervalInSeconds(interval: Int) {
maxInactiveIntervalInSeconds = interval
}
override fun removeAttribute(key: String) {
attributes.remove(key)
}
override fun getAttributeNames() = attributes.keys
override fun <T> getAttribute(key: String): T? = attributes[key] as T?
override fun setAttribute(key: String, value: Any) {
attributes.put(key, value)
}
override fun isExpired() = false
}
This currently works well, but only uses Memcache and needs improvement for high availability.
source to share