Skip to content

Commit

Permalink
added info in DS for sub and iss when user is logging in and account …
Browse files Browse the repository at this point in the history
…is created
  • Loading branch information
twocanoes committed Nov 26, 2023
1 parent 0f75ef5 commit a16e2f5
Show file tree
Hide file tree
Showing 16 changed files with 282 additions and 36 deletions.
48 changes: 42 additions & 6 deletions NomadLogin/DSQueryable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public protocol DSQueryable {}
public extension DSQueryable {

/// `ODNode` to DSLocal for queries and account manipulation.
public var localNode: ODNode? {
var localNode: ODNode? {
do {
os_log("Finding the DSLocal node", type: .debug)
return try ODNode.init(session: ODSession.default(), type: ODNodeType(kODNodeTypeLocalNodes))
Expand All @@ -39,7 +39,7 @@ public extension DSQueryable {
/// - Parameter shortName: The name of the user to search for as a `String`.
/// - Returns: `true` if the user exists in DSLocal, `false` if not.
/// - Throws: Either an `ODFrameworkErrors` or a `DSQueryableErrors` if there is an error or the user is not local.
public func isUserLocal(_ shortName: String) throws -> Bool {
func isUserLocal(_ shortName: String) throws -> Bool {
do {
_ = try getLocalRecord(shortName)
} catch DSQueryableErrors.notLocalUser {
Expand All @@ -57,7 +57,7 @@ public extension DSQueryable {
/// - userPass: The password for the user being tested as a `String`.
/// - Returns: `true` if the name and password combo are valid locally. `false` if the validation fails.
/// - Throws: Either an `ODFrameworkErrors` or a `DSQueryableErrors` if there is an error.
public func isLocalPasswordValid(userName: String, userPass: String) throws -> Bool {
func isLocalPasswordValid(userName: String, userPass: String) throws -> Bool {
do {
let userRecord = try getLocalRecord(userName)
try userRecord.verifyPassword(userPass)
Expand All @@ -79,7 +79,7 @@ public extension DSQueryable {
/// - Parameter shortName: The name of the user to search for as a `String`.
/// - Returns: The `ODRecord` of the user if one is found in DSLocal.
/// - Throws: Either an `ODFrameworkErrors` or a `DSQueryableErrors` if there is an error or the user is not local.
public func getLocalRecord(_ shortName: String) throws -> ODRecord {
func getLocalRecord(_ shortName: String) throws -> ODRecord {
do {
os_log("Building OD query for name %{public}@", type: .default, shortName)
let query = try ODQuery.init(node: localNode,
Expand Down Expand Up @@ -111,7 +111,7 @@ public extension DSQueryable {
///
/// - Returns: A `Array` that contains the `ODRecord` for every account in DSLocal.
/// - Throws: An error from `ODFrameworkErrors` if something fails.
public func getAllLocalUserRecords() throws -> [ODRecord] {
func getAllLocalUserRecords() throws -> [ODRecord] {
do {
let query = try ODQuery.init(node: localNode,
forRecordTypes: kODRecordTypeUsers,
Expand All @@ -126,12 +126,48 @@ public extension DSQueryable {
throw error
}
}
/// Finds OIDC User with specified iss and sub.
///
/// - Returns: A `Array` that contains the `ODRecord` for account in DSLocal
/// - Throws: An error from `ODFrameworkErrors` if something fails.
func getUserRecord(sub:String, iss:String) throws -> ODRecord {
do {
os_log("getting non system users.", type: .info)

let allRecords = try getAllNonSystemUsers()
os_log("filtering", type: .info)

let matchingRecords = allRecords.filter { (record) -> Bool in
guard let issValue = try? record.values(forAttribute: "dsAttrTypeNative:_xcreds_oidc_iss") as? [String] else {
return false
}
guard let subValue = try? record.values(forAttribute: "dsAttrTypeNative:_xcreds_oidc_sub") as? [String] else {
return false
}

os_log("checking \(issValue) \(subValue)", type: .info)

return issValue.first == iss && subValue.first == sub
}
guard let userRecord = matchingRecords.first else {
os_log("no users match iss \(iss) and sub \(sub)", type: .info)

throw DSQueryableErrors.notLocalUser
}
return userRecord
} catch {
os_log("ODError while finding local users.", type: .error)
throw error
}
}


/// Returns all the non-system users on a system above UID 500.
///
/// - Returns: A `Array` that contains the `ODRecord` of all the non-system user accounts in DSLocal.
/// - Throws: An error from `ODFrameworkErrors` if something fails.
public func getAllNonSystemUsers() throws -> [ODRecord] {
///
func getAllNonSystemUsers() throws -> [ODRecord] {
do {
let allRecords = try getAllLocalUserRecords()
let nonSystem = try allRecords.filter { (record) -> Bool in
Expand Down
22 changes: 18 additions & 4 deletions Profile Manifest/com.twocanoes.xcreds.plist
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ Note that Google does not support the offline_access scope so instead use the pr
<key>pfm_default</key>
<false/>
<key>pfm_description</key>
<string>Favor using XCreds' local login screen over the cloud login UI.</string>
<string>Favor using XCreds&apos; local login screen over the cloud login UI.</string>
<key>pfm_documentation_url</key>
<string>https://twocanoes.com/knowledge-base/xcreds-admin-guide/#preferences</string>
<key>pfm_name</key>
Expand Down Expand Up @@ -575,6 +575,20 @@ Note that Google does not support the offline_access scope so instead use the pr
<key>pfm_type</key>
<string>boolean</string>
</dict>
<dict>
<key>pfm_default</key>
<false/>
<key>pfm_description</key>
<string>Prompt for local account username and password if no account was mapped</string>
<key>pfm_documentation_url</key>
<string>https://twocanoes.com/knowledge-base/xcreds-admin-guide/#shouldPromptForMigration</string>
<key>pfm_name</key>
<string>shouldPromptForMigration</string>
<key>pfm_title</key>
<string>Should Prompt for Migration</string>
<key>pfm_type</key>
<string>boolean</string>
</dict>
<dict>
<key>pfm_default</key>
<true/>
Expand Down Expand Up @@ -699,7 +713,7 @@ Note that Google does not support the offline_access scope so instead use the pr
<key>pfm_default</key>
<false/>
<key>pfm_description</key>
<string>Reset the keychain without prompting if the login password doesn't match the local password.</string>
<string>Reset the keychain without prompting if the login password doesn&apos;t match the local password.</string>
<key>pfm_documentation_url</key>
<string>https://twocanoes.com/knowledge-base/xcreds-admin-guide/#preferences</string>
<key>pfm_name</key>
Expand Down Expand Up @@ -808,9 +822,9 @@ Note that Google does not support the offline_access scope so instead use the pr
</dict>
<dict>
<key>pfm_description</key>
<string>Password element id of the html element that has the password. It is read by using JavaScript to get the value (for example, for Azure, the JavaScript document.getElementById('i0118').value is sent. If this default is not set, standard values for Azure and Google Cloud will be used. To find out this value, use a browser to inspect the source of the page that has the password on it. Find the id of the textfield that has the password. Fill in the password and then open the JavaScript console. Run:
<string>Password element id of the html element that has the password. It is read by using JavaScript to get the value (for example, for Azure, the JavaScript document.getElementById(&apos;i0118&apos;).value is sent. If this default is not set, standard values for Azure and Google Cloud will be used. To find out this value, use a browser to inspect the source of the page that has the password on it. Find the id of the textfield that has the password. Fill in the password and then open the JavaScript console. Run:
document.getElementById('passwordID').value
document.getElementById(&apos;passwordID&apos;).value
changing “passwordID” to the correct element ID. If the value you typed into the textfield is returned, this is the correct ID.</string>
<key>pfm_documentation_url</key>
Expand Down
2 changes: 1 addition & 1 deletion XCreds/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import Cocoa

@main
class AppDelegate: NSObject, NSApplicationDelegate {
class AppDelegate: NSObject, NSApplicationDelegate, DSQueryable {

@IBOutlet weak var loginPasswordWindow: NSWindow!
@IBOutlet var window: NSWindow!
Expand Down
2 changes: 1 addition & 1 deletion XCreds/Base.lproj/MainMenu.xib
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="XCreds" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About xCreds" id="5kV-Vb-QxS">
<menuItem title="About XCreds" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
Expand Down
2 changes: 2 additions & 0 deletions XCreds/defaults.plist
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,7 @@
<false/>
<key>passwordPlaceholder</key>
<string>Password</string>
<key>shouldPromptForMigration</key>
<false/>
</dict>
</plist>
2 changes: 2 additions & 0 deletions XCredsLoginPlugIn/ContextAndHintHandling.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ enum HintType: String {
// case noMADLast
// case noMADFull
case adGroups
case oidcSub
case oidcIssuer


}
Expand Down
4 changes: 0 additions & 4 deletions XCredsLoginPlugIn/LoginWindow/ControlsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,13 @@ class ControlsViewController: NSViewController {
// return NSNib.Name("ControlsViewController")
// }
func commandKey(evt: NSEvent) -> NSEvent{
TCSLogWithMark(evt.debugDescription)

let flags = evt.modifierFlags.rawValue & NSEvent.ModifierFlags.command.rawValue
TCSLogWithMark("\(flags.description)")
if flags != 0 { //key code for command is 55
commandKeyDown = true
TCSLogWithMark("command down")
}
else {
commandKeyDown=false
TCSLogWithMark("not command down")

}
return evt
Expand Down
37 changes: 30 additions & 7 deletions XCredsLoginPlugIn/LoginWindow/LoginWebViewWindowController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import WebKit
import OIDCLite
import OpenDirectory

class LoginWebViewWindowController: WebViewWindowController {
class LoginWebViewWindowController: WebViewWindowController, DSQueryable {

let uiLog = "uiLog"
var internalDelegate:XCredsMechanismProtocol?
Expand Down Expand Up @@ -221,12 +221,35 @@ class LoginWebViewWindowController: WebViewWindowController {
}

let idTokenInfo = jwtDecode(value: idToken) //dictionary for mapping
guard let idTokenInfo = idTokenInfo else {
delegate.denyLogin(message:"No idTokenInfo found.")
return
}

// try? getUserRecord(sub: "", iss: "123")

guard let subValue = idTokenInfo["sub"] as? String, let issuerValue = idTokenInfo["iss"] as? String else {
delegate.denyLogin(message:"OIDC token does not contain both a sub and iss value.")
return

}
let existingUser = try? getUserRecord(sub: subValue, iss: issuerValue)

TCSLogWithMark("setting issuer and sub hint from OIDC token")
delegate.setHint(type: .oidcSub, hint: "\(subValue)")
delegate.setHint(type: .oidcIssuer, hint: "\(issuerValue)")

if existingUser != nil, let odUsername = existingUser?.recordName {
TCSLogWithMark("prior local user found.")

username = odUsername

}
// username static map
if let defaultsUsername = defaultsUsername {
else if let defaultsUsername = defaultsUsername {
username = defaultsUsername
}
else if let idTokenInfo = idTokenInfo, let mapKey = DefaultsOverride.standardOverride.object(forKey: "map_username") as? String, mapKey.count>0, let mapValue = idTokenInfo[mapKey] as? String, let leftSide = mapValue.components(separatedBy: "@").first{
else if let mapKey = DefaultsOverride.standardOverride.object(forKey: "map_username") as? String, mapKey.count>0, let mapValue = idTokenInfo[mapKey] as? String, let leftSide = mapValue.components(separatedBy: "@").first{

username = leftSide.replacingOccurrences(of: " ", with: "_").stripped
TCSLogWithMark("mapped username found: \(mapValue) clean version:\(username)")
Expand Down Expand Up @@ -261,7 +284,7 @@ class LoginWebViewWindowController: WebViewWindowController {
//full name
TCSLogWithMark("checking map_fullname")

if let idTokenInfo = idTokenInfo, let mapKey = DefaultsOverride.standardOverride.object(forKey: "map_fullname") as? String, mapKey.count>0, let mapValue = idTokenInfo[mapKey] as? String {
if let mapKey = DefaultsOverride.standardOverride.object(forKey: "map_fullname") as? String, mapKey.count>0, let mapValue = idTokenInfo[mapKey] as? String {
//we have a mapping so use that.
TCSLogWithMark("full name mapped to: \(mapKey)")

Expand All @@ -276,7 +299,7 @@ class LoginWebViewWindowController: WebViewWindowController {

}
//groups
if let idTokenInfo = idTokenInfo,let mapValue = idTokenInfo["groups"] as? Array<String> {
if let mapValue = idTokenInfo["groups"] as? Array<String> {
TCSLogWithMark("setting groups: \(mapValue)")
delegate.setHint(type: .groups, hint:mapValue)
}
Expand All @@ -286,7 +309,7 @@ class LoginWebViewWindowController: WebViewWindowController {
}

//first name
if let idTokenInfo = idTokenInfo, let mapKey = DefaultsOverride.standardOverride.object(forKey: "map_firstname") as? String, mapKey.count>0, let mapValue = idTokenInfo[mapKey] as? String {
if let mapKey = DefaultsOverride.standardOverride.object(forKey: "map_firstname") as? String, mapKey.count>0, let mapValue = idTokenInfo[mapKey] as? String {
//we have a mapping for username, so use that.
TCSLogWithMark("first name mapped to: \(mapKey)")

Expand All @@ -302,7 +325,7 @@ class LoginWebViewWindowController: WebViewWindowController {
//last name
TCSLogWithMark("checking map_lastname")

if let idTokenInfo = idTokenInfo, let mapKey = DefaultsOverride.standardOverride.object(forKey: "map_lastname") as? String, mapKey.count>0, let mapValue = idTokenInfo[mapKey] as? String {
if let mapKey = DefaultsOverride.standardOverride.object(forKey: "map_lastname") as? String, mapKey.count>0, let mapValue = idTokenInfo[mapKey] as? String {
//we have a mapping for lastName, so use that.
TCSLogWithMark("last name mapped to: \(mapKey)")

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// VerifyLocalCredentialsWindowController.swift
// XCredsLoginPlugin
//
// Created by Timothy Perfitt on 11/25/23.
//

import Cocoa

class VerifyLocalCredentialsWindowController: NSWindowController {

@IBOutlet weak var usernameTextField: NSTextField!
@IBOutlet weak var passwordTextField: NSSecureTextField!
override func windowDidLoad() {
super.windowDidLoad()

}

@IBAction func okButtonPressed(_ sender: Any) {
}
@IBAction func cancelButtonPressed(_ sender: Any) {
}
}

0 comments on commit a16e2f5

Please sign in to comment.