#42: Proof of concept login via OIDC.

Uses AppAuth library in the app, ignoring token refresh
This commit is contained in:
Doug
2022-07-28 09:28:42 +01:00
committed by GitHub
parent f8c30a7341
commit c20bc6bd1c
20 changed files with 323 additions and 57 deletions
@@ -110,8 +110,6 @@ class AuthenticationCoordinator: Coordinator, Presentable {
switch action {
case .signedIn(let userSession):
self.delegate?.authenticationCoordinator(self, didLoginWithSession: userSession)
case .continueWithOIDC:
break
}
}
@@ -14,6 +14,7 @@
// limitations under the License.
//
import AppAuth
import MatrixRustSDK
import SwiftUI
@@ -27,8 +28,6 @@ struct LoginCoordinatorParameters {
enum LoginCoordinatorAction {
/// Login was successful.
case signedIn(UserSessionProtocol)
/// Continue using OIDC.
case continueWithOIDC
}
final class LoginCoordinator: Coordinator, Presentable {
@@ -39,6 +38,8 @@ final class LoginCoordinator: Coordinator, Presentable {
private let parameters: LoginCoordinatorParameters
private let loginHostingController: UIViewController
private var loginViewModel: LoginViewModelProtocol
/// Passed to the OIDC service to provide a view controller from which to present the authentication session.
private let oidcUserAgent: OIDExternalUserAgentIOS?
private var currentTask: Task<Void, Error>? {
willSet {
@@ -69,6 +70,7 @@ final class LoginCoordinator: Coordinator, Presentable {
loginHostingController = UIHostingController(rootView: view)
indicatorPresenter = UserIndicatorTypePresenter(presentingViewController: loginHostingController)
oidcUserAgent = OIDExternalUserAgentIOS(presenting: loginHostingController)
}
// MARK: - Public
@@ -90,7 +92,7 @@ final class LoginCoordinator: Coordinator, Presentable {
case .login(let username, let password):
self.login(username: username, password: password)
case .continueWithOIDC:
self.callback?(.continueWithOIDC)
self.loginWithOIDC()
}
}
}
@@ -138,6 +140,26 @@ final class LoginCoordinator: Coordinator, Presentable {
}
}
private func loginWithOIDC() {
guard let oidcUserAgent = oidcUserAgent else {
handleError(AuthenticationServiceError.oidcError(.notSupported))
return
}
startLoading(isInteractionBlocking: true)
Task {
switch await authenticationService.loginWithOIDC(userAgent: oidcUserAgent) {
case .success(let userSession):
callback?(.signedIn(userSession))
stopLoading()
case .failure(let error):
stopLoading()
handleError(error)
}
}
}
/// Requests the authentication coordinator to log in using the specified credentials.
private func login(username: String, password: String) {
startLoading(isInteractionBlocking: true)
@@ -53,7 +53,8 @@ final class HomeScreenCoordinator: Coordinator, Presentable {
init(parameters: HomeScreenCoordinatorParameters) {
self.parameters = parameters
viewModel = HomeScreenViewModel(attributedStringBuilder: parameters.attributedStringBuilder)
viewModel = HomeScreenViewModel(initialDisplayName: parameters.userSession.userID,
attributedStringBuilder: parameters.attributedStringBuilder)
let view = HomeScreen(context: viewModel.context)
hostingController = UIHostingController(rootView: view)
@@ -31,7 +31,7 @@ enum HomeScreenViewAction {
}
struct HomeScreenViewState: BindableState {
var userDisplayName: String?
var userDisplayName: String
var userAvatar: UIImage?
var showSessionVerificationBanner = false
@@ -39,10 +39,11 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
// MARK: - Setup
init(attributedStringBuilder: AttributedStringBuilderProtocol) {
init(initialDisplayName: String, attributedStringBuilder: AttributedStringBuilderProtocol) {
self.attributedStringBuilder = attributedStringBuilder
super.init(initialViewState: HomeScreenViewState(isLoadingRooms: true))
super.init(initialViewState: HomeScreenViewState(userDisplayName: initialDisplayName,
isLoadingRooms: true))
}
// MARK: - Public
@@ -84,7 +84,7 @@ struct HomeScreen: View {
}
}
}
@ViewBuilder
private var userAvatarImage: some View {
if let avatar = context.viewState.userAvatar {
@@ -94,21 +94,14 @@ struct HomeScreen: View {
.frame(width: 32, height: 32, alignment: .center)
.clipShape(Circle())
.accessibilityIdentifier("userAvatarImage")
} else {
EmptyView()
}
}
@ViewBuilder
private var userDisplayNameView: some View {
if let displayName = context.viewState.userDisplayName {
Text(displayName)
.font(.headline)
.fontWeight(.bold)
.foregroundColor(.primary)
} else {
EmptyView()
}
Text(context.viewState.userDisplayName)
.font(.headline)
.fontWeight(.bold)
.foregroundColor(.primary)
}
}
@@ -173,11 +166,14 @@ struct RoomCell: View {
struct HomeScreen_Previews: PreviewProvider {
static var previews: some View {
body.preferredColorScheme(.light)
.tint(.element.accent)
body.preferredColorScheme(.dark)
.tint(.element.accent)
}
static var body: some View {
let viewModel = HomeScreenViewModel(attributedStringBuilder: AttributedStringBuilder())
let viewModel = HomeScreenViewModel(initialDisplayName: "@username:server.com",
attributedStringBuilder: AttributedStringBuilder())
let eventBrief = EventBrief(eventId: "id",
senderId: "senderId",