Skip to content

Commit

Permalink
adding arbitrary claims to local DS user account
Browse files Browse the repository at this point in the history
  • Loading branch information
twocanoes committed Nov 30, 2023
1 parent 51387b1 commit e47832e
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 84 deletions.
21 changes: 20 additions & 1 deletion Profile Manifest/com.twocanoes.xcreds.plist
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<key>pfm_app_url</key>
<string>https://github.com/twocanoes/xcreds</string>
<key>pfm_description</key>
<string>XCreds 3.3 (5273) OAuth Settings</string>
<string>XCreds 3.3 (5310) OAuth Settings</string>
<key>pfm_documentation_url</key>
<string>https://twocanoes.com/knowledge-base/xcreds-admin-guide/#preferences</string>
<key>pfm_domain</key>
Expand Down Expand Up @@ -194,6 +194,25 @@ A profile can consist of payloads with different version numbers. For example, c
<key>pfm_type</key>
<string>array</string>
</dict>
<dict>
<key>pfm_description</key>
<string>List of claims that should be added to the user local account. Will be prefixed with _xcreds_oidc_. Set as an Array of Strings of the claim.</string>
<key>pfm_name</key>
<string>claimsToAddToLocalUserAccount</string>
<key>pfm_subkeys</key>
<array>
<dict>
<key>pfm_name</key>
<string>claim</string>
<key>pfm_type</key>
<string>string</string>
</dict>
</array>
<key>pfm_title</key>
<string>Claims To Add To Local User Account</string>
<key>pfm_type</key>
<string>array</string>
</dict>
<dict>
<key>pfm_default</key>
<false/>
Expand Down
2 changes: 1 addition & 1 deletion XCreds/PrefKeys.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Foundation

enum PrefKeys: String {
case clientID, clientSecret, password="xcreds local password",discoveryURL, redirectURI, scopes, accessToken, idToken, refreshToken, tokenEndpoint, expirationDate, invalidToken, refreshRateHours,refreshRateMinutes, showDebug, verifyPassword, shouldShowQuitMenu, shouldShowPreferencesOnStart, shouldSetGoogleAccessTypeToOffline, passwordChangeURL, shouldShowAboutMenu, username, idpHostName, passwordElementID, shouldFindPasswordElement, shouldShowVersionInfo, shouldShowSupportStatus,shouldShowConfigureWifiButton,shouldShowMacLoginButton, loginWindowBackgroundImageURL, shouldShowCloudLoginByDefault, shouldPreferLocalLoginInsteadOfCloudLogin, idpHostNames,autoRefreshLoginTimer, loginWindowWidth, loginWindowHeight, shouldShowRefreshBanner, shouldSwitchToLoginWindowWhenLocked,accounts = "Accounts",
windowSignIn = "WindowSignIn", settingsOverrideScriptPath, localAdminUserName, localAdminPassword, usernamePlaceholder, passwordPlaceholder, shouldShowLocalOnlyCheckbox, shouldShowTokenUpdateStatus, shouldDetectNetworkToDetermineLoginWindow, showLoginWindowDelaySeconds, shouldPromptForMigration, shouldAllowKeyComboForMacLoginWindow, aliasName
windowSignIn = "WindowSignIn", settingsOverrideScriptPath, localAdminUserName, localAdminPassword, usernamePlaceholder, passwordPlaceholder, shouldShowLocalOnlyCheckbox, shouldShowTokenUpdateStatus, shouldDetectNetworkToDetermineLoginWindow, showLoginWindowDelaySeconds, shouldPromptForMigration, shouldAllowKeyComboForMacLoginWindow, aliasName,claimsToAddToLocalUserAccount
//, filePathToPreventShowingUI
case ropgClientID
case ropgClientSecret
Expand Down
4 changes: 4 additions & 0 deletions XCreds/defaults.plist
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,9 @@
<false/>
<key>shouldAllowKeyComboForMacLoginWindow</key>
<false/>
<key>claimsToAddToLocalUserAccount</key>
<array>
<string>groups</string>
</array>
</dict>
</plist>
5 changes: 3 additions & 2 deletions XCredsLoginPlugIn/ContextAndHintHandling.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ enum HintType: String {
// case noMADLast
// case noMADFull
case adGroups
case oidcSub
case oidcIssuer
// case oidcSub
// case oidcIssuer
case aliasName
case claimsToAddToLocalUserAccount


}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,9 +261,9 @@ class LoginWebViewWindowController: WebViewWindowController, DSQueryable {
let standardUsers = try? getAllStandardUsers()
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)")
// TCSLogWithMark("setting issuer and sub hint from OIDC token")
// delegate.setHint(type: .oidcSub, hint: "\(subValue)")
// delegate.setHint(type: .oidcIssuer, hint: "\(issuerValue)")
let aliasClaim = DefaultsOverride.standardOverride.string(forKey: PrefKeys.aliasName.rawValue)
if let aliasClaim = aliasClaim, let aliasClaimValue = idTokenInfo[aliasClaim] {
TCSLogWithMark("found alias claim: \(aliasClaim):\(aliasClaimValue)")
Expand Down
47 changes: 1 addition & 46 deletions XCredsLoginPlugIn/Mechanisms/XCredsBaseMechanism.swift
Original file line number Diff line number Diff line change
Expand Up @@ -274,52 +274,7 @@ protocol XCredsMechanismProtocol {

return true
}
class func updateOIDCInfo(user: String, iss:String?, sub:String?, groups:[String]?) -> Bool {
os_log("Checking for local username", log: noLoMechlog, type: .default)
var records = [ODRecord]()
let odsession = ODSession.default()
do {
let node = try ODNode.init(session: odsession, type: ODNodeType(kODNodeTypeLocalNodes))
let query = try ODQuery.init(node: node, forRecordTypes: kODRecordTypeUsers, attribute: kODAttributeTypeRecordName, matchType: ODMatchType(kODMatchEqualTo), queryValues: user, returnAttributes: kODAttributeTypeAllAttributes, maximumResults: 0)
records = try query.resultsAllowingPartial(false) as! [ODRecord]
} catch {
let errorText = error.localizedDescription
os_log("ODError while trying to check for local user: %{public}@", log: noLoMechlog, type: .error, errorText)
return false
}

let isLocal = records.isEmpty ? false : true
os_log("Results of local user check %{public}@", log: noLoMechlog, type: .default, isLocal.description)

if !isLocal {
return isLocal
}

// now to update the attribute

do {
os_log("updating sub",log: noLoMechlog, type: .error)

try records.first?.setValue(sub, forAttribute: "dsAttrTypeNative:_xcreds_oidc_sub")


os_log("updating iss",log: noLoMechlog, type: .error)

try records.first?.setValue(iss, forAttribute: "dsAttrTypeNative:_xcreds_oidc_iss")


if let groups = groups?.joined(separator: ";") {
try records.first?.setValue(groups, forAttribute: "dsAttrTypeNative:_xcreds_oidc_groups")

}
} catch {
os_log("Unable to add OIDC Info", log: noLoMechlog, type: .error)
return false
}

return true

}

/// Set one of the known `AuthorizationTags` values to be used during mechanism evaluation.
///
/// - Parameters:
Expand Down
145 changes: 120 additions & 25 deletions XCredsLoginPlugIn/Mechanisms/XCredsCreateUser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,6 @@ class XCredsCreateUser: XCredsBaseMechanism, DSQueryable {
let currentDate = ISO8601DateFormatter().string(from: Date())
customAttributes["dsAttrTypeNative:\(metaPrefix)_creationDate"] = currentDate

if let oidcSubHint = getHint(type: .oidcSub) as? String {
customAttributes["dsAttrTypeNative:\(metaPrefix)_oidc_sub"] = oidcSubHint
}
if let oidcIssHint = getHint(type: .oidcIssuer) as? String {
customAttributes["dsAttrTypeNative:\(metaPrefix)_oidc_iss"] = oidcIssHint
}

guard let xcredsFirst=xcredsFirst, let xcredsLast = xcredsLast else {
TCSLogErrorWithMark("first or last name not defined. bailing")
Expand Down Expand Up @@ -200,24 +194,15 @@ class XCredsCreateUser: XCredsBaseMechanism, DSQueryable {
}

}

var sub:String?
var iss:String?
var alias:String?
if let oidcSubHint = getHint(type: .oidcSub) as? String {
sub=oidcSubHint
}
if let oidcIssHint = getHint(type: .oidcIssuer) as? String {
iss=oidcIssHint
}

if let aliasHint = getHint(type: .aliasName) as? String {
alias=aliasHint
}
// Set the xcreds attributes to stamp this account as the mapped one
setTimestampFor(xcredsUser ?? "")
if let iss = iss, let sub = sub {
updateOIDCInfo(xcredsUser ?? "", iss: iss, sub:sub, groups:groups)
}
let _ = updateOIDCInfo(user: xcredsUser ?? "")

if let alias = alias, let xcredsUser = xcredsUser {
if XCredsCreateUser.addAlias(name: xcredsUser, alias: alias)==false {
os_log("error adding alias", log: createUserLog, type: .debug)
Expand Down Expand Up @@ -245,6 +230,114 @@ class XCredsCreateUser: XCredsBaseMechanism, DSQueryable {
os_log("CreateUser mech complete", log: createUserLog, type: .debug)
}

func updateOIDCInfo(user: String) -> Bool {
os_log("Checking for local username", log: noLoMechlog, type: .default)
var records = [ODRecord]()
let odsession = ODSession.default()
do {
let node = try ODNode.init(session: odsession, type: ODNodeType(kODNodeTypeLocalNodes))
let query = try ODQuery.init(node: node, forRecordTypes: kODRecordTypeUsers, attribute: kODAttributeTypeRecordName, matchType: ODMatchType(kODMatchEqualTo), queryValues: user, returnAttributes: kODAttributeTypeAllAttributes, maximumResults: 0)
records = try query.resultsAllowingPartial(false) as! [ODRecord]
} catch {
let errorText = error.localizedDescription
os_log("ODError while trying to check for local user: %{public}@", log: noLoMechlog, type: .error, errorText)
return false
}

let isLocal = records.isEmpty ? false : true
os_log("Results of local user check %{public}@", log: noLoMechlog, type: .default, isLocal.description)

if !isLocal {
return false
}

// now to update the attribute
TCSLogWithMark("updating claims in DS")
let claimsToDSArray = (DefaultsOverride.standardOverride.array(forKey: PrefKeys.claimsToAddToLocalUserAccount.rawValue) ?? []) as? [String]

let tokenArray = getHint(type: .tokens) as? Array<String>

if let tokenArray = tokenArray , tokenArray.count>0{
TCSLogWithMark("Found claims")
let idToken = tokenArray[0]
let idTokenInfo = jwtDecode(value: idToken) //dictionary for mapping
if let idTokenInfo = idTokenInfo {
TCSLogWithMark("Decoded Claims")
if var claimsToDSArray = claimsToDSArray {

claimsToDSArray.append("iss")
claimsToDSArray.append("sub")

for currClaim in claimsToDSArray {
TCSLogWithMark("Found Matching Claim: \(currClaim)")
if let value = idTokenInfo[currClaim] as? String {
let sanitizedKey = currClaim.oidc_allowed_chars
if sanitizedKey.count<20 || value.count<256 {
TCSLogWithMark("Adding \(sanitizedKey) = \(value)")
try? records.first?.setValue(value, forAttribute: "dsAttrTypeNative:_xcreds_oidc_\(sanitizedKey)")

}
else {
TCSLogWithMark("key or value too long to put into DS")
}

}
else if let value = idTokenInfo[currClaim] as? Array<String> {
let sanitizedKey = currClaim.oidc_allowed_chars
let oneLine = value.joined(separator: ";")
if sanitizedKey.count<256 || oneLine.count<20 {
TCSLogWithMark("Adding \(sanitizedKey) = \(oneLine)")

try? records.first?.setValue(oneLine, forAttribute: "dsAttrTypeNative:_xcreds_oidc_\(sanitizedKey)")
}
else {
TCSLogWithMark("key or value too long to put into DS")
}
}
}
}
}
}

// var sub:String?
// var iss:String?
// if let oidcSubHint = getHint(type: .oidcSub) as? String {
// sub=oidcSubHint
// }
// if let oidcIssHint = getHint(type: .oidcIssuer) as? String {
// iss=oidcIssHint
// }
//
// if let oidcSubHint = getHint(type: .oidcSub) as? String {
// customAttributes["dsAttrTypeNative:\(metaPrefix)_oidc_sub"] = oidcSubHint
// }
// if let oidcIssHint = getHint(type: .oidcIssuer) as? String {
// customAttributes["dsAttrTypeNative:\(metaPrefix)_oidc_iss"] = oidcIssHint
// }

// do {
// os_log("updating sub",log: noLoMechlog, type: .error)
//
// try records.first?.setValue(sub, forAttribute: "dsAttrTypeNative:_xcreds_oidc_sub")
//
//
// os_log("updating iss",log: noLoMechlog, type: .error)
//
// try records.first?.setValue(iss, forAttribute: "dsAttrTypeNative:_xcreds_oidc_iss")
//
//
//// if let groups = groups?.joined(separator: ";") {
//// try records.first?.setValue(groups, forAttribute: "dsAttrTypeNative:_xcreds_oidc_groups")
////
//// }
// } catch {
// os_log("Unable to add OIDC Info", log: noLoMechlog, type: .error)
// return false
// }

return true

}
func createHome(xcredsUser:String, uid:String) {
TCSLogWithMark("Creating local homefolder for \(xcredsUser)")
createHomeDirFor(xcredsUser)
Expand Down Expand Up @@ -672,13 +765,7 @@ class XCredsCreateUser: XCredsBaseMechanism, DSQueryable {
}

}
fileprivate func updateOIDCInfo(_ user: String, iss:String, sub:String,groups:[String]?) {
if XCredsCreateUser.updateOIDCInfo(user:user, iss: iss, sub:sub, groups:groups) {
os_log("updateOIDCInfo updated", log: createUserLog, type: .default)
} else {
os_log("Could not add updateOIDCInfo", log: createUserLog, type: .error)
}
}



fileprivate func addSecureToken(_ username: String, _ userPass: String?,_ adminUsername: String,_ adminPassword: String?) {
Expand Down Expand Up @@ -813,3 +900,11 @@ class XCredsCreateUser: XCredsBaseMechanism, DSQueryable {
// }

}
extension String {
var oidc_allowed_chars: String {
var allowed = CharacterSet()
allowed.formUnion(CharacterSet.alphanumerics)
allowed.insert(charactersIn: "_#")
return self.components(separatedBy: allowed.inverted).joined()
}
}
12 changes: 6 additions & 6 deletions xCreds.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1253,7 +1253,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 5300;
CURRENT_PROJECT_VERSION = 5310;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = UXP6YEHSPW;
FRAMEWORK_SEARCH_PATHS = (
Expand Down Expand Up @@ -1291,7 +1291,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 5300;
CURRENT_PROJECT_VERSION = 5310;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = UXP6YEHSPW;
FRAMEWORK_SEARCH_PATHS = (
Expand Down Expand Up @@ -1411,7 +1411,7 @@
CODE_SIGN_ENTITLEMENTS = "XCreds Login Overlay/XCreds_Login_Overlay.entitlements";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 5300;
CURRENT_PROJECT_VERSION = 5310;
DEVELOPMENT_TEAM = UXP6YEHSPW;
ENABLE_HARDENED_RUNTIME = YES;
FRAMEWORK_SEARCH_PATHS = (
Expand Down Expand Up @@ -1448,7 +1448,7 @@
CODE_SIGN_ENTITLEMENTS = "XCreds Login Overlay/XCreds_Login_Overlay.entitlements";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 5300;
CURRENT_PROJECT_VERSION = 5310;
DEVELOPMENT_TEAM = UXP6YEHSPW;
ENABLE_HARDENED_RUNTIME = YES;
FRAMEWORK_SEARCH_PATHS = (
Expand Down Expand Up @@ -1598,7 +1598,7 @@
CODE_SIGN_ENTITLEMENTS = XCreds/xCreds.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 5300;
CURRENT_PROJECT_VERSION = 5310;
DEVELOPMENT_TEAM = UXP6YEHSPW;
ENABLE_HARDENED_RUNTIME = YES;
FRAMEWORK_SEARCH_PATHS = (
Expand Down Expand Up @@ -1639,7 +1639,7 @@
CODE_SIGN_ENTITLEMENTS = XCreds/xCreds.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 5300;
CURRENT_PROJECT_VERSION = 5310;
DEVELOPMENT_TEAM = UXP6YEHSPW;
ENABLE_HARDENED_RUNTIME = YES;
FRAMEWORK_SEARCH_PATHS = (
Expand Down
Binary file not shown.

0 comments on commit e47832e

Please sign in to comment.