Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ui improvement and FIDO authentication integration #8828

Merged
merged 14 commits into from
Jul 2, 2024
Merged
31 changes: 19 additions & 12 deletions demos/jans-chip/android/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,28 @@

## A first party android mobile application that leverages dynamic client registration (DCR), DPoP access tokens.

[Demo Video](https://youtu.be/rqPewmESJb0)
[Demo Video](https://www.loom.com/embed/66e145e3bba4406ebda53715168ca8f9?sid=e946f580-587e-4c55-8ea8-3845d6ae4ce9)


### Steps followed in App for authentication

1. DCR with attestation
2. Execute Authorization Challenge Endpoint to get the Authorization Code
3. Generate DPoP Token using Authorization Code and DPoP header
#### Enrolment

![](./docs/enrolment.png)

#### Authentication

![](./docs/authentication.png)

### Auth Challenge Script

Add following [Auth Challenge Script](./docs/authChallengeScript.java) in Jans Server (before using the App) with following details.

- **Name of Script** : passkey_auth_challenge
- **Script Type** : Authorization Challenge
- **Programming Language** : Java
- **Location Type**: Database
- Add `fido2_server_uri` custom property with https://{fido_server_url} as value. Replace `{fido_server_url}` with fido server hostname.

### Workspace Setup

Expand All @@ -20,14 +35,6 @@
3. Press `ctrl` key twice on Android Studio to open `Run Anything` dialog.
4. Enter `gradle wrapper --gradle-version 8.0` and press enter key. This will generate gradle wrapper at `{jans_monorep_path}\demos\jans-chip\gradle\wrapper`.
5. Build and run project on an emmulator (in Android Studio).
6. After launch add configuration endpoint of Janssen Server (with a trusted
domain, not self-signed certificate) and desired scopes on the register screen
to start testing.

## To-Dos

- Add FIDO authentication in app.



**Reference:**
Expand Down
88 changes: 66 additions & 22 deletions demos/jans-chip/android/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,52 +1,96 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("com.google.devtools.ksp")
kotlin("kapt")
}

android {
namespace = "io.jans.chip"
compileSdk = 33
namespace = "io.jans.jans_chip"
compileSdk = 34

defaultConfig {
applicationId = "io.jans.chip"
minSdk = 24
targetSdk = 33
applicationId = "io.jans.jans_chip"
minSdk = 28
targetSdk = 34
versionCode = 1
versionName = "1.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.4.3"
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
}

dependencies {
val room_version = "2.5.2"

implementation("androidx.room:room-runtime:$room_version")
annotationProcessor("androidx.room:room-compiler:$room_version")

implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.9.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
implementation("com.squareup.okhttp3:okhttp:5.0.0-alpha.11")
implementation("com.google.code.google-collections:google-collect:snapshot-20080530")

implementation(project(mapOf("path" to ":webauthn")))
implementation("io.coil-kt:coil-compose:2.6.0")
//implementation("androidx.credentials:credentials:1.3.0-alpha01")
val roomVersion = "2.5.2"
implementation("androidx.room:room-ktx:$roomVersion")
ksp("androidx.room:room-compiler:$roomVersion")
implementation("androidx.compose.material:material-icons-extended:1.5.4")
implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
implementation("androidx.activity:activity-compose:1.8.2")
implementation(platform("androidx.compose:compose-bom:2023.03.00"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3:1.1.1")
implementation("androidx.core:core-splashscreen:1.1.0-rc01")
implementation("androidx.navigation:navigation-compose:2.8.0-alpha06")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1-Beta")
implementation("com.squareup.retrofit2:retrofit:2.11.0")
implementation("com.squareup.retrofit2:converter-gson:2.11.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1-Beta")
implementation("com.nimbusds:nimbus-jose-jwt:9.31")
implementation("io.jsonwebtoken:jjwt:0.9.1")
implementation("javax.xml.bind:jaxb-api:2.4.0-b180830.0359")
implementation("com.nimbusds:nimbus-jose-jwt:9.31")
implementation("com.google.android.play:integrity:1.2.0")
implementation("android.arch.lifecycle:viewmodel:1.1.1")
implementation ("androidx.appcompat:appcompat:1.4.0")
implementation("androidx.biometric:biometric:1.2.0-alpha05")
implementation("com.github.MahboubehSeyedpour:jetpack-loading:1.1.0")

testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00"))
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
}

kapt {
correctErrorTypes = true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.jans.chip

import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4

import org.junit.Test
import org.junit.runner.RunWith

import org.junit.Assert.*

/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("io.jans.jans_chip1", appContext.packageName)
}
}
15 changes: 4 additions & 11 deletions demos/jans-chip/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,16 @@
android:theme="@style/Theme.Janschip"
tools:targetApi="31">
<activity
android:name=".AfterLoginActivity"
android:exported="false" />
<activity
android:name=".LoginActivity"
android:exported="false" />
<activity
android:name=".SplashScreenActivity"
android:exported="true">
android:name="io.jans.chip.MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".RegisterActivity"
android:exported="false" />
</application>

</manifest>

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package io.jans.chip

import android.content.Context
import android.util.Log
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase

import io.jans.chip.model.OPConfiguration
import io.jans.chip.utils.AppConfig
import io.jans.chip.dao.AppIntegrityDao
import io.jans.chip.dao.FidoConfigurationDao
import io.jans.chip.dao.OPConfigurationDao
import io.jans.chip.dao.OidcClientDao
import io.jans.chip.model.OIDCClient
import io.jans.chip.model.appIntegrity.AppIntegrityEntity
import io.jans.chip.model.fido.config.FidoConfiguration


@Database(
entities = [OIDCClient::class, OPConfiguration::class, AppIntegrityEntity::class, FidoConfiguration::class],
version = AppConfig.ROOM_DATABASE_VERSION
)
abstract class AppDatabase : RoomDatabase() {
abstract fun oidcClientDao(): OidcClientDao
abstract fun opConfigurationDao(): OPConfigurationDao
abstract fun appIntegrityDao(): AppIntegrityDao
abstract fun fidoConfigurationDao(): FidoConfigurationDao

companion object {
private val LOG_TAG = AppDatabase::class.java.simpleName
private val LOCK = Any()
private val DATABASE_NAME: String = AppConfig.SQLITE_DB_NAME
private var instance: AppDatabase? = null
fun getInstance(context: Context): AppDatabase {
if (instance == null) {
synchronized(LOCK) {
Log.d(
LOG_TAG,
"Creating new database instance"
)
instance = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java, DATABASE_NAME
)
.allowMainThreadQueries()
.fallbackToDestructiveMigration()
.build()
}
Log.d(LOG_TAG, "Getting the database instance")
}
return instance!!
}
}

}
Loading