Merge branch 'housekeeping/refactoring-oauth-2' into 'develop'

Improving OAuth implementation

See merge request funkwhale/funkwhale-android!78
This commit is contained in:
Ryan Harg 2021-08-27 09:15:16 +00:00
commit c45c6d21e0
2 changed files with 34 additions and 13 deletions

View File

@ -56,25 +56,21 @@ class OAuth(private val authorizationServiceFactory: AuthorizationServiceFactory
fun isAuthorized(context: Context): Boolean { fun isAuthorized(context: Context): Boolean {
val state = tryState() val state = tryState()
return if (state != null) { return (if (state != null) {
state.isAuthorized || refreshAccessToken(context) state.validAuthorization() || refreshAccessToken(state, context)
} else { } else {
false false
}.also { }).also {
it.logInfo("isAuthorized()") it.logInfo("isAuthorized()")
} }
} }
private fun AuthState.validAuthorization() = this.isAuthorized && !this.needsTokenRefresh
fun tryRefreshAccessToken(context: Context): Boolean { fun tryRefreshAccessToken(context: Context): Boolean {
tryState()?.let { state -> tryState()?.let { state ->
return if (state.needsTokenRefresh && state.refreshToken != null) { return if (state.needsTokenRefresh && state.refreshToken != null) {
Log.i( refreshAccessToken(state, context)
"OAuth",
"needsTokenRefresh()=${state.needsTokenRefresh}, refreshToken=${
state.refreshToken!!.subSequence(0, 5)
}..."
)
refreshAccessToken(context)
} else { } else {
state.isAuthorized state.isAuthorized
}.also { it.logInfo("tryRefreshAccessToken()") } }.also { it.logInfo("tryRefreshAccessToken()") }
@ -83,9 +79,12 @@ class OAuth(private val authorizationServiceFactory: AuthorizationServiceFactory
} }
fun refreshAccessToken(context: Context): Boolean { fun refreshAccessToken(context: Context): Boolean {
return tryState()?.let { refreshAccessToken(it, context) } ?: false
}
private fun refreshAccessToken(state: AuthState, context: Context): Boolean {
Log.i("OAuth", "refreshAccessToken()") Log.i("OAuth", "refreshAccessToken()")
val state = tryState() return if (state.refreshToken != null) {
return if (state != null && state.refreshToken != null) {
val refreshRequest = state.createTokenRefreshRequest() val refreshRequest = state.createTokenRefreshRequest()
val auth = ClientSecretPost(state.clientSecret) val auth = ClientSecretPost(state.clientSecret)
runBlocking { runBlocking {

View File

@ -131,13 +131,35 @@ class OAuthTest {
} }
@Test @Test
fun `isAuthorized() should return true if existing state is authorized`() { fun `isAuthorized() should return true if existing state is authorized and token needs no refresh`() {
mockkStatic(PowerPreference::class) mockkStatic(PowerPreference::class)
mockkStatic(AuthState::class) mockkStatic(AuthState::class)
val authState = mockk<AuthState>() val authState = mockk<AuthState>()
every { AuthState.jsonDeserialize(any<String>()) } returns authState every { AuthState.jsonDeserialize(any<String>()) } returns authState
every { authState.isAuthorized } returns true every { authState.isAuthorized } returns true
every { authState.needsTokenRefresh } returns false
val mockPref = mockk<Preference>()
every { PowerPreference.getFileByName(any()) } returns mockPref
every { mockPref.getString(any()) } returns "{}"
expectThat(oAuth.isAuthorized(context)).isTrue()
}
@Test
fun `isAuthorized() should return true if existing state is authorized and token needs refresh`() {
mockkStatic(PowerPreference::class)
mockkStatic(AuthState::class)
val authState = mockk<AuthState>()
every { AuthState.jsonDeserialize(any<String>()) } returns authState
every { authState.isAuthorized } returns true
every { authState.needsTokenRefresh } returns true
every { authState.refreshToken } returns "refreshToken"
every { authState.createTokenRefreshRequest() } returns mockk()
every { authState.clientSecret } returns "clientSecret"
every { authServiceFactory.create(any()) } returns authService
val mockPref = mockk<Preference>() val mockPref = mockk<Preference>()
every { PowerPreference.getFileByName(any()) } returns mockPref every { PowerPreference.getFileByName(any()) } returns mockPref