-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5f4268c
commit 130dbf9
Showing
23 changed files
with
476 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
Authorization/Authorization/Presentation/SSO/ContainerWebView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// | ||
// ContainerWebView.swift | ||
// Authorization | ||
// | ||
// Created by Rawan Matar on 02/06/2024. | ||
// | ||
|
||
import SwiftUI | ||
import Core | ||
import Swinject | ||
|
||
public struct ContainerWebView: View { | ||
|
||
// MARK: - Internal Properties | ||
|
||
let url: String | ||
private var pageTitle: String | ||
@Environment(\.presentationMode) var presentationMode | ||
|
||
// MARK: - Init | ||
|
||
public init(_ url: String, title: String) { | ||
self.url = url | ||
self.pageTitle = title | ||
} | ||
|
||
// MARK: - UI | ||
|
||
public var body: some View { | ||
VStack(alignment: .center) { | ||
NavigationBar( | ||
title: pageTitle, | ||
leftButtonAction: { presentationMode.wrappedValue.dismiss() } | ||
) | ||
|
||
ZStack { | ||
if !url.isEmpty { | ||
SSOWebView(url: URL(string: url), viewModel: Container.shared.resolve(SSOWebViewModel.self)!) | ||
} else { | ||
EmptyView() | ||
} | ||
} | ||
.accessibilityIdentifier("web_browser") | ||
} | ||
} | ||
} |
73 changes: 73 additions & 0 deletions
73
Authorization/Authorization/Presentation/SSO/SSOHelper.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// | ||
// SSOHelper.swift | ||
// Authorization | ||
// | ||
// Created by Rawan Matar on 02/06/2024. | ||
// | ||
|
||
import Foundation | ||
|
||
// https://developer.apple.com/documentation/ios-ipados-release-notes/foundation-release-notes | ||
|
||
/** | ||
A Helper for some of the SSO preferences. | ||
Keeps data under the UserDefaults. | ||
*/ | ||
public class SSOHelper: NSObject { | ||
|
||
public enum UserDefaultKeys: String, CaseIterable { | ||
case cookiePayload | ||
case cookieSignature | ||
case userInfo | ||
|
||
var description: String { | ||
switch self { | ||
case .cookiePayload: | ||
return "edx-jwt-cookie-header-payload" | ||
case .cookieSignature: | ||
return "edx-jwt-cookie-signature" | ||
case .userInfo: | ||
return "edx-user-info" | ||
} | ||
} | ||
} | ||
|
||
// MARK: - Singleton | ||
|
||
public static let shared = SSOHelper() | ||
|
||
// MARK: - Public Properties | ||
|
||
/// Authentication | ||
public var cookiePayload: String? { | ||
get { | ||
let defaults = UserDefaults.standard | ||
return defaults.string(forKey: UserDefaultKeys.cookiePayload.rawValue) | ||
} | ||
set (newValue) { | ||
let defaults = UserDefaults.standard | ||
defaults.set(newValue, forKey: UserDefaultKeys.cookiePayload.rawValue) | ||
} | ||
} | ||
|
||
/// Authentication | ||
public var cookieSignature: String? { | ||
get { | ||
let defaults = UserDefaults.standard | ||
return defaults.string(forKey: UserDefaultKeys.cookieSignature.rawValue) | ||
} | ||
set (newValue) { | ||
let defaults = UserDefaults.standard | ||
defaults.set(newValue, forKey: UserDefaultKeys.cookieSignature.rawValue) | ||
} | ||
} | ||
|
||
// MARK: - Public Methods | ||
|
||
/// Checks if the user is login. | ||
public func cleanAfterSuccesfulLogout() { | ||
cookiePayload = nil | ||
cookieSignature = nil | ||
} | ||
} | ||
|
104 changes: 104 additions & 0 deletions
104
Authorization/Authorization/Presentation/SSO/SSOWebView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
// | ||
// SSOWebView.swift | ||
// Authorization | ||
// | ||
// Created by Rawan Matar on 02/06/2024. | ||
// | ||
|
||
|
||
import SwiftUI | ||
import WebKit | ||
import Core | ||
|
||
public struct SAMLConstants { | ||
|
||
public init() {} | ||
|
||
public let samlLoginSuccess = URL(string: "https://blue.zeitlabs.com/auth/complete/tpa-saml")! | ||
} | ||
|
||
public struct SSOWebView: UIViewRepresentable { | ||
|
||
let url: URL? | ||
|
||
var viewModel: SSOWebViewModel | ||
|
||
public init(url: URL?, viewModel: SSOWebViewModel) { | ||
self.url = url | ||
self.viewModel = viewModel | ||
} | ||
|
||
public func makeUIView(context: Context) -> WKWebView { | ||
let coordinator = makeCoordinator() | ||
let userContentController = WKUserContentController() | ||
userContentController.add(coordinator, name: "bridge") | ||
|
||
let prefs = WKWebpagePreferences() | ||
let config = WKWebViewConfiguration() | ||
prefs.allowsContentJavaScript = true | ||
|
||
config.userContentController = userContentController | ||
config.defaultWebpagePreferences = prefs | ||
config.websiteDataStore = WKWebsiteDataStore.nonPersistent() | ||
|
||
let wkWebView = WKWebView(frame: .zero, configuration: config) | ||
wkWebView.navigationDelegate = coordinator | ||
|
||
guard let currentURL = url else { | ||
return wkWebView | ||
} | ||
let request = URLRequest(url: currentURL) | ||
wkWebView.load(request) | ||
|
||
return wkWebView | ||
} | ||
|
||
public func updateUIView(_ uiView: WKWebView, context: Context) { | ||
|
||
} | ||
|
||
public func makeCoordinator() -> Coordinator { | ||
Coordinator(viewModel: self.viewModel) | ||
} | ||
|
||
public class Coordinator: NSObject, WKScriptMessageHandler, WKNavigationDelegate { | ||
var viewModel: SSOWebViewModel | ||
|
||
init(viewModel: SSOWebViewModel) { | ||
self.viewModel = viewModel | ||
super.init() | ||
} | ||
|
||
// WKScriptMessageHandler | ||
public func userContentController(_ userContentController: WKUserContentController, | ||
didReceive message: WKScriptMessage) { | ||
} | ||
|
||
// WKNavigationDelegate | ||
public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { | ||
guard let _ = webView.url?.absoluteString else { | ||
return | ||
} | ||
|
||
} | ||
|
||
public func webView(_ webView: WKWebView, | ||
decidePolicyFor navigationAction: WKNavigationAction, | ||
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { | ||
guard let url = webView.url?.absoluteString else { | ||
decisionHandler(.allow) | ||
return | ||
} | ||
|
||
if url.contains(SAMLConstants().samlLoginSuccess.absoluteString) { | ||
webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in | ||
Task { | ||
await self.viewModel.SSOLogin(cookies: cookies) | ||
} | ||
} | ||
} | ||
|
||
decisionHandler(.allow) | ||
} | ||
} | ||
} |
Oops, something went wrong.