Skip to content

Commit

Permalink
[RFR-265] Switch to OAuth (#54)
Browse files Browse the repository at this point in the history
* [RFR-469] Add draft for oauth authentication

* Upgrade SDK to test version

* Remove unused code

* Attempt to merge TokenActivity into MainActivity

* Add debug messages

* WIP: fresh token is provided

* [RFR-519] Fix logout

* Add dummy implementation

* Update build.gradle

* [RFR-563] Inject oauth config

* Last working state for rfr UI

* Cleanup

* Fix build

* Disable Notification test

* Upgrade SDK to 7.8.0
  • Loading branch information
hb0 authored Jun 19, 2023
1 parent c8b04da commit 901034f
Show file tree
Hide file tree
Showing 40 changed files with 1,562 additions and 2,582 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/gradle_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,12 @@ jobs:
echo "githubToken=${{ secrets.GH_READ_TOKEN }}" >> gradle.properties
# This mock API accepts all credentials and allows the UI test to skip the login
echo "cyface.staging_api=https://demo.cyface.de/api/v2" >> gradle.properties
echo "cyface.staging_auth_api=https://demo.cyface.de/api/v2" >> gradle.properties
echo "cyface.staging_incentives_api=https://demo.cyface.de/incentives" >> gradle.properties
echo "cyface.staging_oauth_discovery=https://demo.cyface.de/auth" >> gradle.properties
echo "cyface.staging_user=guestLogin" >> gradle.properties
echo "cyface.staging_password=guestPassword" >> gradle.properties
echo "cyface.oauth_redirect=de.cyface.app:/oauth2redirect" >> gradle.properties
echo "cyface.oauth_redirect.r4r=de.cyface.app.r4r:/oauth2redirect" >> gradle.properties
# Executing build here on Ubuntu stack (1/10th costs of MacOS stack)
# Not using "gradle build" as we don't want to run the tests of all dependencies (e.g. backend)
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/gradle_connected-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,12 @@ jobs:
run: |
# This mock API accepts all credentials and allows the UI test to skip the login
echo "cyface.staging_api=https://demo.cyface.de/api/v2" >> gradle.properties
echo "cyface.staging_auth_api=https://demo.cyface.de/api/v2" >> gradle.properties
echo "cyface.staging_incentives_api=https://demo.cyface.de/incentives" >> gradle.properties
echo "cyface.staging_oauth_discovery=https://demo.cyface.de/auth" >> gradle.properties
echo "cyface.staging_user=guestLogin" >> gradle.properties
echo "cyface.staging_password=guestPassword" >> gradle.properties
echo "cyface.oauth_redirect=de.cyface.app:/oauth2redirect" >> gradle.properties
echo "cyface.oauth_redirect.r4r=de.cyface.app.r4r:/oauth2redirect" >> gradle.properties
# Not executing build here on MacOS stack (10x costs, if private repository)
# Not using "gradle build" as we don't want to run the tests of all dependencies (e.g. backend)
Expand Down
2 changes: 1 addition & 1 deletion README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ To download the Cyface libraries (SDK, Energy Settings, Camera Service):

[arabic]
* You need a Github account with read-access to these Github repositories
* Create a https://github.com/settings/tokens[personal access token on Github] with "write:packages" permissions
* Create a https://github.com/settings/tokens[personal access token on Github] with `read:packages` and `repo` permissions to download the sub-modules and `android-publish` dependency.
* Copy `gradle.properties.template` to `gradle.properties` and adjust:
+
....
Expand Down
2 changes: 1 addition & 1 deletion backend
Submodule backend updated 32 files
+3 −0 build.gradle
+7 −0 datacapturing/build.gradle
+15 −0 datacapturing/src/androidTest/java/de/cyface/datacapturing/TestUtils.java
+6 −5 datacapturing/src/androidTestCyface/java/de/cyface/datacapturing/DataCapturingServiceTest.kt
+3 −3 ...capturing/src/androidTestCyface/java/de/cyface/datacapturing/DataCapturingServiceWithoutPermissionTest.java
+4 −4 datacapturing/src/androidTestCyface/java/de/cyface/datacapturing/PingPongTest.kt
+9 −9 datacapturing/src/cyface/java/de/cyface/datacapturing/CyfaceDataCapturingService.java
+25 −11 datacapturing/src/main/java/de/cyface/datacapturing/DataCapturingService.kt
+1 −1 datacapturing/src/movebis/java/de/cyface/datacapturing/MovebisDataCapturingService.kt
+0 −1 persistence/src/main/java/de/cyface/persistence/DefaultPersistenceLayer.kt
+0 −7 persistence/src/main/java/de/cyface/persistence/dao/DefaultFileDao.kt
+10 −0 synchronization/build.gradle
+7 −0 synchronization/src/androidTest/java/de/cyface/synchronization/MockAuth.kt
+1 −3 synchronization/src/androidTestCyface/java/de/cyface/synchronization/CyfaceAuthenticatorTest.java
+1 −2 synchronization/src/androidTestCyface/java/de/cyface/synchronization/SyncAdapterTest.kt
+1 −1 synchronization/src/androidTestCyface/java/de/cyface/synchronization/UploadProgressTest.kt
+149 −0 synchronization/src/cyface/java/de/cyface/synchronization/AuthStateManager.kt
+225 −0 synchronization/src/cyface/java/de/cyface/synchronization/Configuration.kt
+128 −0 synchronization/src/cyface/java/de/cyface/synchronization/ConnectionBuilderForTesting.java
+0 −249 synchronization/src/cyface/java/de/cyface/synchronization/CyfaceAuthenticator.java
+167 −0 synchronization/src/cyface/java/de/cyface/synchronization/CyfaceAuthenticator.kt
+282 −0 synchronization/src/cyface/java/de/cyface/synchronization/OAuth2.kt
+81 −0 synchronization/src/cyface/java/de/cyface/synchronization/SyncService.kt
+12 −0 synchronization/src/main/java/de/cyface/synchronization/Auth.kt
+3 −5 synchronization/src/main/java/de/cyface/synchronization/AuthenticatorService.java
+170 −170 synchronization/src/main/java/de/cyface/synchronization/SyncAdapter.kt
+0 −232 synchronization/src/main/java/de/cyface/synchronization/SyncPerformer.java
+305 −0 synchronization/src/main/java/de/cyface/synchronization/SyncPerformer.kt
+0 −103 synchronization/src/main/java/de/cyface/synchronization/SyncService.java
+1 −4 synchronization/src/movebis/java/de/cyface/synchronization/CyfaceAuthenticator.java
+7 −0 synchronization/src/movebis/java/de/cyface/synchronization/MovebisAuth.kt
+80 −0 synchronization/src/movebis/java/de/cyface/synchronization/SyncService.kt
4 changes: 3 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ ext {
*/

// Cyface dependencies
cyfaceAndroidBackendVersion = "7.7.2" // Also update submodule commit ref
cyfaceAndroidBackendVersion = "7.8.0" // Also update submodule commit ref
cyfaceUtilsVersion = "3.3.7"
cyfaceEnergySettingsVersion = "3.3.3" // Also update submodule commit ref
cyfaceCameraServiceVersion = "4.1.11" // Also update submodule commit ref
Expand Down Expand Up @@ -87,6 +87,8 @@ ext {
materialDialogsVersion = "3.3.0"
chartVersion = "v3.1.0"
hCaptchaVersion = "3.8.1"
// Can't be a SDK dependency as `appAuthRedirectScheme` needs to be defined at build-time
appAuthVersion = "0.11.1" // Can't move to uploader lib because of dependency issues

// Testing
junitVersion = "1.1.5"
Expand Down
29 changes: 21 additions & 8 deletions gradle.properties.template
Original file line number Diff line number Diff line change
Expand Up @@ -31,28 +31,41 @@ android.nonTransitiveRClass=true

android.builder.sdkDownload=true
android.enableJetifier=false
android.defaults.buildfeatures.buildconfig=true
android.nonFinalResIds=false

githubUser=
githubToken=

cyface.api=
cyface.auth_api=
cyface.incentives_api=

google.maps_api_key=
google.maps-api_key.r4r=

hCaptcha.key=
hCaptcha.key.r4r=

cyface.demo_api=
cyface.local_api=
cyface.emulator_api=
cyface.oauth_redirect=
cyface.oauth_redirect.r4r=

cyface.api=
cyface.incentives_api=
cyface.oauth_discovery=

cyface.staging_api=
cyface.staging_auth_api=
cyface.staging_incentives_api=
cyface.staging_oauth_discovery=
cyface.staging_user=
cyface.staging_password=

cyface.demo_api=
cyface.demo_incentives_api=
cyface.demo_oauth_discovery=

cyface.local_api=
cyface.local_incentives_api=
cyface.local_oauth_discovery=

cyface.emulator_api=
cyface.emulator_incentives_api=
cyface.emulator_oauth_discovery=

# keep an empty line at the end for the CI to inject new lines easily
29 changes: 25 additions & 4 deletions ui/cyface/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,19 @@ android {
missingDimensionStrategy 'project', 'cyface'
missingDimensionStrategy 'mode', 'full'

// Load Google Maps API key
manifestPlaceholders = [ googleMapsApiKey:"${project.findProperty('google.maps_api_key')}"]
// Placeholders for AndroidManifest.xml
manifestPlaceholders = [
// Load Google Maps API key
googleMapsApiKey:"${project.findProperty('google.maps_api_key')}",

// Define app link scheme for AppAuth redirect
// Ensure this is consistent with the redirect URI defined below in `oauthRedirect`
// or specify additional redirect URIs in AndroidManifest.xml
'appAuthRedirectScheme': 'de.cyface.app'
]

// oauth redirect uri
buildConfigField "String", "oauthRedirect", "\"${project.findProperty('cyface.oauth_redirect')}\""

// Load hCaptcha API key
buildConfigField "String", "hCaptchaKey", "\"${project.findProperty('hCaptcha.key')}\""
Expand All @@ -86,26 +97,32 @@ android {

// Phone - to local collector - ! only if iptables allow connection from outside
//buildConfigField "String", "cyfaceServer", "\"${project.findProperty('cyface.local_api')}\""
//buildConfigField "String", "oauthDiscovery", "\"${project.findProperty('cyface.local_oauth_discovery')}\""
//manifestPlaceholders = [usesCleartextTraffic:"true"]

// Phone - to local production - ! only if iptables allow connection from outside
// CertPathValidatorException: Trust anchor for certification path not found.
//buildConfigField "String", "cyfaceServer", "\"${project.findProperty('cyface.local_production_api')}\""
//buildConfigField "String", "oauthDiscovery", "\"${project.findProperty('cyface.local_oauth_discovery')}\""
//manifestPlaceholders = [usesCleartextTraffic:"false"]

// EMULATOR - to local collector
//buildConfigField "String", "cyfaceServer", "\"${project.findProperty('cyface.emulator_api')}\""
//buildConfigField "String", "oauthDiscovery", "\"${project.findProperty('cyface.emulator_oauth_discovery')}\""
//manifestPlaceholders = [usesCleartextTraffic:"true"] // for local collector testing

// Staging
buildConfigField "String", "cyfaceServer", "\"${project.findProperty('cyface.staging_api')}\""
buildConfigField "String", "authServer", "\"${project.findProperty('cyface.staging_auth_api')}\""
buildConfigField "String", "incentivesServer", "\"${project.findProperty('cyface.staging_incentives_api')}\""
buildConfigField "String", "oauthDiscovery", "\"${project.findProperty('cyface.staging_oauth_discovery')}\""
buildConfigField "String", "testLogin", "\"${project.findProperty('cyface.staging_user')}\""
buildConfigField "String", "testPassword", "\"${project.findProperty('cyface.staging_password')}\""
manifestPlaceholders = [usesCleartextTraffic:"false"]

// MOCK-API - only supports login - used by UI test on CI
//buildConfigField "String", "cyfaceServer", "\"${project.findProperty('cyface.demo_api')}\""
//buildConfigField "String", "incentivesServer", "\"${project.findProperty('cyface.demo_incentives_api')}\""
//buildConfigField "String", "oauthDiscovery", "\"${project.findProperty('cyface.demo_oauth_discovery')}\""
//manifestPlaceholders = [usesCleartextTraffic:"false"] // for local collector testing
}
release {
Expand All @@ -116,7 +133,8 @@ android {

// signingConfig is set by the CI
buildConfigField "String", "cyfaceServer", "\"${project.findProperty('cyface.api')}\""
buildConfigField "String", "authServer", "\"${project.findProperty('cyface.auth_api')}\""
buildConfigField "String", "incentivesServer", "\"${project.findProperty('cyface.incentives_api')}\""
buildConfigField "String", "oauthDiscovery", "\"${project.findProperty('cyface.oauth_discovery')}\""
manifestPlaceholders = [usesCleartextTraffic:"false"]
}
}
Expand Down Expand Up @@ -205,6 +223,9 @@ dependencies {
// HCaptcha
implementation "com.github.hcaptcha:hcaptcha-android-sdk:$rootProject.ext.hCaptchaVersion"

// OAuth 2.0 with OpenID Connect
implementation "net.openid:appauth:$rootProject.ext.appAuthVersion" // Move to uploader [RFR-581]

// Cyface dependencies
implementation "de.cyface:android-utils:$rootProject.ext.cyfaceUtilsVersion"
implementation project(':datacapturing')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import org.hamcrest.CoreMatchers
import org.hamcrest.MatcherAssert
import org.hamcrest.Matchers
import org.junit.Before
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
Expand Down Expand Up @@ -104,6 +105,7 @@ class CapturingNotificationTest {
* This test is flaky on the Bitrise CI.
*/
@Test
@Ignore("OAuth needs to be skipped [RFR-587]")
fun test() {
val context = InstrumentationRegistry.getInstrumentation().targetContext

Expand Down
13 changes: 7 additions & 6 deletions ui/cyface/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,15 @@
<!-- allowBackup=false as we did not yet define what we really want to backup-->
<!-- usesCleartextTraffic only API 23+, ignored below. only for debugging -->
<!-- tools:ignore = UnusedAttribute required to ignore Lint warning (usesCleartextTraffic) -->
<!-- tools:replace="android:usesCleartextTraffic" required when testing against local collector -->
<application
android:name=".MeasuringClient"
android:allowBackup="false"
android:icon="@mipmap/ic_logo"
android:label="@string/app_name"
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute"
tools:replace="android:usesCleartextTraffic"
android:usesCleartextTraffic="${usesCleartextTraffic}">

<!-- Sentry DSN. This ids the account but is not a secret. -->
Expand Down Expand Up @@ -81,22 +83,21 @@
</intent-filter>
</activity>

<!-- See https://github.com/openid/AppAuth-Android/blob/master/app/AndroidManifest.xml
for more details on how to handle AppAuth redirects and app links. Activity is called by LoginActivity. -->
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"> <!-- needed so that we don't have "two activities" when opening the activity via the notification bar and hitting the back button -->
</activity>

<!-- The LoginActivity automatically launched by the SDK's CyfaceAuthenticator -->
<activity
android:name=".LoginActivity"
android:name=".auth.LoginActivity"
android:label="@string/title_activity_login"
android:exported="false"
android:launchMode="singleTask" /> <!-- when we switch back from Registration, see https://stackoverflow.com/a/45292292/5815054 -->

<!-- The RegistrationActivity can be launched via (on top of) the LoginActivity -->
<activity
android:name=".RegistrationActivity"
android:label="@string/sign_up" />

<!-- This overwrites the provider in the SDK. This way the app can be installed next to other SDK using apps -->
<!-- But we replaced the Content Provider with a Stub Content provider. -->
<provider
Expand Down
3 changes: 1 addition & 2 deletions ui/cyface/src/main/kotlin/de/cyface/app/CapturingFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,7 @@ class CapturingFragment : Fragment(), ConnectionStatusListener {
requireActivity().supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
requireActivity().addMenuProvider(
MenuProvider(
capturing,
requireActivity(),
requireActivity() as MainActivity,
navHostFragment.navController
),
viewLifecycleOwner,
Expand Down
Loading

0 comments on commit 901034f

Please sign in to comment.