Skip to content

Commit 4b4b3c3

Browse files
authored
feat: add single sign on by saml (#420)
* revert: Support for login and registration via a browser custom tab (#371) This reverts commit 4566b1a * feat: add saml sso * fix: resolve conflicts and unit test * fix: unit test issues * fix: sso login flow and other fixes * fix: sso login unit tests * fix: sso login flow handle cookies error and display a message and other fixes * fix: fixing detekt issues * fix: merge fixes * fix: fix detekt and unit tests issues * fix: fix detekt issues * fix: fix detekt issues * fix: fix detekt issues
1 parent 035eea9 commit 4b4b3c3

File tree

32 files changed

+641
-578
lines changed

32 files changed

+641
-578
lines changed

app/schemas/org.openedx.app.room.AppDatabase/4.json

Lines changed: 80 additions & 172 deletions
Large diffs are not rendered by default.

app/src/main/AndroidManifest.xml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,6 @@
4848

4949
<category android:name="android.intent.category.LAUNCHER" />
5050
</intent-filter>
51-
<intent-filter>
52-
<action android:name="android.intent.action.VIEW" />
53-
<category android:name="android.intent.category.DEFAULT" />
54-
<category android:name="android.intent.category.BROWSABLE" />
55-
<data android:scheme="${applicationId}" />
56-
</intent-filter>
5751

5852
<!-- Branch URI Scheme -->
5953
<intent-filter>

app/src/main/java/org/openedx/app/AppActivity.kt

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@ package org.openedx.app
22

33
import android.content.Intent
44
import android.content.res.Configuration
5-
import android.graphics.Color
6-
import android.net.Uri
7-
import android.os.Build
85
import android.os.Bundle
96
import android.view.View
107
import android.view.WindowManager
@@ -26,7 +23,6 @@ import org.openedx.app.databinding.ActivityAppBinding
2623
import org.openedx.app.deeplink.DeepLink
2724
import org.openedx.auth.presentation.logistration.LogistrationFragment
2825
import org.openedx.auth.presentation.signin.SignInFragment
29-
import org.openedx.core.ApiConstants
3026
import org.openedx.core.data.storage.CorePreferences
3127
import org.openedx.core.presentation.dialog.downloaddialog.DownloadDialogManager
3228
import org.openedx.core.presentation.global.InsetHolder
@@ -70,13 +66,6 @@ class AppActivity : AppCompatActivity(), InsetHolder, WindowSizeHolder {
7066
private val authCode: String?
7167
get() {
7268
val data = intent?.data
73-
if (
74-
data is Uri &&
75-
data.scheme == BuildConfig.APPLICATION_ID &&
76-
data.host == ApiConstants.BrowserLogin.REDIRECT_HOST
77-
) {
78-
return data.getQueryParameter(ApiConstants.BrowserLogin.CODE_QUERY_PARAM)
79-
}
8069
return null
8170
}
8271

@@ -160,12 +149,8 @@ class AppActivity : AppCompatActivity(), InsetHolder, WindowSizeHolder {
160149
WindowCompat.setDecorFitsSystemWindows(this, false)
161150
val insetsController = WindowInsetsControllerCompat(this, binding.root)
162151
insetsController.isAppearanceLightStatusBars = !isUsingNightModeResources()
163-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
164-
insetsController.systemBarsBehavior =
165-
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
166-
} else {
167-
window.statusBarColor = Color.TRANSPARENT
168-
}
152+
insetsController.systemBarsBehavior =
153+
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
169154
}
170155
}
171156

@@ -176,7 +161,7 @@ class AppActivity : AppCompatActivity(), InsetHolder, WindowSizeHolder {
176161
val fragment = if (viewModel.isLogistrationEnabled && authCode == null) {
177162
LogistrationFragment()
178163
} else {
179-
SignInFragment.newInstance(null, null, authCode = authCode)
164+
SignInFragment.newInstance(null, null)
180165
}
181166
addFragment(fragment)
182167
}
@@ -224,7 +209,7 @@ class AppActivity : AppCompatActivity(), InsetHolder, WindowSizeHolder {
224209
this.intent = intent
225210

226211
if (authCode != null) {
227-
addFragment(SignInFragment.newInstance(null, null, authCode = authCode))
212+
addFragment(SignInFragment.newInstance(null, null))
228213
}
229214

230215
val extras = intent.extras

app/src/main/java/org/openedx/app/AppRouter.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import org.openedx.core.CalendarRouter
1313
import org.openedx.core.FragmentViewType
1414
import org.openedx.core.presentation.global.appupgrade.AppUpgradeRouter
1515
import org.openedx.core.presentation.global.appupgrade.UpgradeRequiredFragment
16+
import org.openedx.core.presentation.global.webview.SSOWebContentFragment
1617
import org.openedx.core.presentation.global.webview.WebContentFragment
1718
import org.openedx.core.presentation.settings.video.VideoQualityFragment
1819
import org.openedx.core.presentation.settings.video.VideoQualityType
@@ -434,6 +435,13 @@ class AppRouter :
434435
)
435436
}
436437

438+
override fun navigateToSSOWebContent(fm: FragmentManager, title: String, url: String) {
439+
replaceFragmentWithBackStack(
440+
fm,
441+
SSOWebContentFragment.newInstance(title = title, url = url)
442+
)
443+
}
444+
437445
override fun navigateToManageAccount(fm: FragmentManager) {
438446
replaceFragmentWithBackStack(fm, ManageAccountFragment())
439447
}

app/src/main/java/org/openedx/app/di/AppModule.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import org.openedx.app.room.DatabaseManager
2323
import org.openedx.auth.presentation.AgreementProvider
2424
import org.openedx.auth.presentation.AuthAnalytics
2525
import org.openedx.auth.presentation.AuthRouter
26-
import org.openedx.auth.presentation.sso.BrowserAuthHelper
2726
import org.openedx.auth.presentation.sso.FacebookAuthHelper
2827
import org.openedx.auth.presentation.sso.GoogleAuthHelper
2928
import org.openedx.auth.presentation.sso.MicrosoftAuthHelper
@@ -224,7 +223,6 @@ val appModule = module {
224223
factory { FacebookAuthHelper() }
225224
factory { GoogleAuthHelper(get()) }
226225
factory { MicrosoftAuthHelper() }
227-
factory { BrowserAuthHelper(get()) }
228226
factory { OAuthHelper(get(), get(), get()) }
229227
factory { VideoPreviewHelper(get(), get()) }
230228

app/src/main/java/org/openedx/app/di/ScreenModule.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.openedx.app.di
22

3+
import android.content.res.Resources
34
import org.koin.core.module.dsl.viewModel
45
import org.koin.core.qualifier.named
56
import org.koin.dsl.module
@@ -113,11 +114,11 @@ val screenModule = module {
113114
get(),
114115
get(),
115116
get(),
116-
get(),
117117
)
118118
}
119119

120-
viewModel { (courseId: String?, infoType: String?, authCode: String) ->
120+
val lang = Resources.getSystem().configuration.locales[0].language
121+
viewModel { (courseId: String?, infoType: String?) ->
121122
SignInViewModel(
122123
get(),
123124
get(),
@@ -135,7 +136,8 @@ val screenModule = module {
135136
get(),
136137
courseId,
137138
infoType,
138-
authCode,
139+
lang,
140+
get()
139141
)
140142
}
141143

auth/src/main/java/org/openedx/auth/data/api/AuthApi.kt

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,6 @@ interface AuthApi {
3737
@Field("asymmetric_jwt") isAsymmetricJwt: Boolean = true,
3838
): AuthResponse
3939

40-
@FormUrlEncoded
41-
@POST(ApiConstants.URL_ACCESS_TOKEN)
42-
suspend fun getAccessTokenFromCode(
43-
@Field("grant_type") grantType: String,
44-
@Field("client_id") clientId: String,
45-
@Field("code") code: String,
46-
@Field("redirect_uri") redirectUri: String,
47-
@Field("token_type") tokenType: String,
48-
@Field("asymmetric_jwt") isAsymmetricJwt: Boolean = true,
49-
): AuthResponse
50-
5140
@FormUrlEncoded
5241
@POST(ApiConstants.URL_ACCESS_TOKEN)
5342
fun refreshAccessToken(

auth/src/main/java/org/openedx/auth/data/model/AuthType.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,4 @@ enum class AuthType(val postfix: String, val methodName: String) {
1313
GOOGLE(ApiConstants.AUTH_TYPE_GOOGLE, "Google"),
1414
FACEBOOK(ApiConstants.AUTH_TYPE_FB, "Facebook"),
1515
MICROSOFT(ApiConstants.AUTH_TYPE_MICROSOFT, "Microsoft"),
16-
BROWSER(ApiConstants.AUTH_TYPE_BROWSER, "Browser")
1716
}

auth/src/main/java/org/openedx/auth/data/repository/AuthRepository.kt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ class AuthRepository(
3131
.processAuthResponse()
3232
}
3333

34+
suspend fun ssoLogin(
35+
jwtToken: String
36+
) {
37+
if (preferencesManager.accessToken.isBlank()) {
38+
preferencesManager.accessToken = jwtToken
39+
}
40+
val user = api.getProfile()
41+
preferencesManager.user = user
42+
}
43+
3444
suspend fun socialLogin(token: String?, authType: AuthType) {
3545
require(!token.isNullOrBlank()) { "Token is null" }
3646
api.exchangeAccessToken(
@@ -43,16 +53,6 @@ class AuthRepository(
4353
.processAuthResponse()
4454
}
4555

46-
suspend fun browserAuthCodeLogin(code: String) {
47-
api.getAccessTokenFromCode(
48-
grantType = ApiConstants.GRANT_TYPE_CODE,
49-
clientId = config.getOAuthClientId(),
50-
code = code,
51-
redirectUri = "${config.getAppId()}://${ApiConstants.BrowserLogin.REDIRECT_HOST}",
52-
tokenType = config.getAccessTokenType(),
53-
).mapToDomain().processAuthResponse()
54-
}
55-
5656
suspend fun getRegistrationFields(): List<RegistrationField> {
5757
return api.getRegistrationFields().fields?.map { it.mapToDomain() } ?: emptyList()
5858
}

auth/src/main/java/org/openedx/auth/domain/interactor/AuthInteractor.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ class AuthInteractor(private val repository: AuthRepository) {
1414
repository.login(username, password)
1515
}
1616

17-
suspend fun loginSocial(token: String?, authType: AuthType) {
18-
repository.socialLogin(token, authType)
17+
suspend fun ssoLogin(
18+
jwtToken: String
19+
) {
20+
repository.ssoLogin(jwtToken)
1921
}
2022

21-
suspend fun loginAuthCode(authCode: String) {
22-
repository.browserAuthCodeLogin(authCode)
23+
suspend fun loginSocial(token: String?, authType: AuthType) {
24+
repository.socialLogin(token, authType)
2325
}
2426

2527
suspend fun getRegistrationFields(): List<RegistrationField> {

0 commit comments

Comments
 (0)