Skip to content

Commit

Permalink
ADST-422 (#73)
Browse files Browse the repository at this point in the history
* added auth0 authentication

* added secured parameter for Auth0

* code correction
  • Loading branch information
aman-alfresco authored Jul 5, 2024
1 parent 6df13b7 commit 3c88794
Show file tree
Hide file tree
Showing 20 changed files with 604 additions and 270 deletions.
4 changes: 2 additions & 2 deletions auth/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ apply plugin: 'org.jetbrains.dokka'
android {
namespace 'com.alfresco.auth'
defaultConfig {
versionName "0.8.1"
versionName "0.8.2"
}
}

dependencies {
implementation libs.appauth
implementation libs.jwtdecode

implementation libs.auth0
implementation libs.kotlin.serialization.json

implementation libs.androidx.appcompat
Expand Down
14 changes: 12 additions & 2 deletions auth/src/main/java/com/alfresco/auth/AuthConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,16 @@ data class AuthConfig(
/**
* Path to content service
*/
var contentServicePath: String
var contentServicePath: String,

/**
* scheme for Auth0
*/
var scheme: String = "",
/**
* selected AuthType
*/
var authType: String = ""
) {
/**
* Convenience method for JSON serialization.
Expand All @@ -51,7 +60,8 @@ data class AuthConfig(
/**
* Convenience method for deserializing a JSON string representation.
*/
@JvmStatic fun jsonDeserialize(str: String): AuthConfig? {
@JvmStatic
fun jsonDeserialize(str: String): AuthConfig? {
return try {
Json.decodeFromString(serializer(), str)
} catch (ex: SerializationException) {
Expand Down
18 changes: 18 additions & 0 deletions auth/src/main/java/com/alfresco/auth/AuthInterceptor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class AuthInterceptor(
provider = when (authType) {
AuthType.BASIC -> BasicProvider(stateString)
AuthType.PKCE -> PkceProvider(stateString, config)
AuthType.OIDC -> OIDCProvider(stateString)
AuthType.UNKNOWN -> PlainProvider()
}
}
Expand Down Expand Up @@ -224,10 +225,27 @@ class AuthInterceptor(
}
}

private inner class OIDCProvider (val accessToken : String) : Provider{
override fun intercept(chain: Interceptor.Chain): Response {
val response = chain.proceed(AuthType.OIDC, accessToken)

// If still error notify listener of failure
if (response.code == HTTP_RESPONSE_401_UNAUTHORIZED) {
listener?.onAuthFailure(accountId, response.request.url.toString())
}
return response
}

override fun finish() {
localScope.coroutineContext.cancelChildren()
}
}

private fun Interceptor.Chain.proceed(type: AuthType, token: String?): Response {
val headerValue = when (type) {
AuthType.BASIC -> "Basic $token"
AuthType.PKCE -> "Bearer $token"
AuthType.OIDC -> "bearer $token"
AuthType.UNKNOWN -> null
}
return proceedWithAuthorization(headerValue)
Expand Down
5 changes: 5 additions & 0 deletions auth/src/main/java/com/alfresco/auth/AuthType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ enum class AuthType(val value: String) {
*/
PKCE("pkce"),

/**
* Used to specify the need of SSO auth
*/
OIDC("oidc"),

/**
* Used to specify that the auth type is unknown
*/
Expand Down
6 changes: 5 additions & 1 deletion auth/src/main/java/com/alfresco/auth/Credentials.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,9 @@ data class Credentials(
/**
* String representation of authentication type.
*/
val authType: String
val authType: String,

val hostName: String = "",

val clientId: String = ""
)
60 changes: 57 additions & 3 deletions auth/src/main/java/com/alfresco/auth/DiscoveryService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ package com.alfresco.auth

import android.content.Context
import android.net.Uri
import com.alfresco.auth.data.AppConfigDetails
import com.alfresco.auth.data.ContentServerDetails
import com.alfresco.auth.data.ContentServerDetailsData
import com.alfresco.auth.pkce.PkceAuthService
import java.net.URL
import java.util.concurrent.TimeUnit
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import okhttp3.Request
import java.net.URL
import java.util.concurrent.TimeUnit

/**
* Class that facilitates service discovery process.
Expand All @@ -24,10 +25,27 @@ class DiscoveryService(
* Determine which [AuthType] is supported by the [endpoint].
*/
suspend fun getAuthType(endpoint: String): AuthType {

when (authConfig.authType.lowercase()) {
AuthType.OIDC.value -> {
if (isOIDC(endpoint)) {
return AuthType.OIDC
}
}

AuthType.PKCE.value -> {
if (isPkceType(endpoint)) {
return AuthType.PKCE
}
}
}

return when {

isPkceType(endpoint) -> AuthType.PKCE

isOIDC(endpoint) -> AuthType.OIDC

isBasicType(endpoint) -> AuthType.BASIC

else -> AuthType.UNKNOWN
Expand Down Expand Up @@ -62,6 +80,31 @@ class DiscoveryService(
}
}

suspend fun isOIDCInstalled(appConfigURL: String): Boolean {
val uri = PkceAuthService.discoveryUriWithAuth0(appConfigURL).toString()
return withContext(Dispatchers.IO) {
try {
val client = OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.build()
val request = Request.Builder()
.url(URL(uri))
.get()
.build()
val response = client.newCall(request).execute()

if (response.code != 200) return@withContext false

val body = response.body?.string() ?: ""
val data = AppConfigDetails.jsonDeserialize(body)
return@withContext data?.oauth2?.audience?.isNotBlank() == true
} catch (e: Exception) {
e.printStackTrace()
false
}
}
}

/**
* returns content server details based on [endpoint].
*/
Expand Down Expand Up @@ -97,10 +140,15 @@ class DiscoveryService(
val result = try {
val authService = PkceAuthService(context, null, authConfig)
authService.fetchDiscoveryFromUrl(uri)
} catch (exception: Exception) { null }
} catch (exception: Exception) {
null
}
return result != null
}

private suspend fun isOIDC(endpoint: String): Boolean =
isOIDCInstalled(endpoint) && authConfig.realm.isBlank()

/**
* Return content service url based on [endpoint].
*/
Expand All @@ -110,6 +158,12 @@ class DiscoveryService(
.appendPath(authConfig.contentServicePath)
.build()

fun oidcUrl(endpoint: String): Uri =
PkceAuthService.endpointWith(endpoint, authConfig)
.buildUpon()
.appendPath("alfresco")
.build()

private fun contentServiceDiscoveryUrl(endpoint: String): Uri =
contentServiceUrl(endpoint)
.buildUpon()
Expand Down
42 changes: 42 additions & 0 deletions auth/src/main/java/com/alfresco/auth/data/AppConfigDetails.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.alfresco.auth.data

import kotlinx.serialization.Serializable
import kotlinx.serialization.SerializationException
import kotlinx.serialization.json.Json

@Serializable
data class OAuth2Data(
val host: String,
val clientId: String,
val secret: String,
val scope: String,
val implicitFlow: Boolean,
val codeFlow: Boolean,
val silentLogin: Boolean,
val publicUrls: List<String>,
val redirectSilentIframeUri: String,
val redirectUri: String,
val logoutUrl: String,
val logoutParameters: List<String>,
val redirectUriLogout: String,
val audience: String,
val skipIssuerCheck: Boolean,
val strictDiscoveryDocumentValidation: Boolean
)

@Serializable
internal data class AppConfigDetails(
val oauth2: OAuth2Data
) {
companion object {
private val json = Json { ignoreUnknownKeys = true }

fun jsonDeserialize(str: String): AppConfigDetails? {
return try {
json.decodeFromString(serializer(), str)
} catch (ex: SerializationException) {
null
}
}
}
}
Loading

0 comments on commit 3c88794

Please sign in to comment.