Skip to content

Instantly share code, notes, and snippets.

@MagerValp
Last active June 19, 2018 02:56
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MagerValp/293ad5a311eaa685dd8ee8380e8dccb8 to your computer and use it in GitHub Desktop.
Save MagerValp/293ad5a311eaa685dd8ee8380e8dccb8 to your computer and use it in GitHub Desktop.

FixAuthAuth

Here are my scripts to fix accounts affected by an extraneous apostrophe in the Authentication Authority after being migrated from mobile to local, as written up in Rich's blog post. While I've successfull rolled them out in our environment, I had to remove some site specific logic before publishing them here, so make sure you test them carefully.

#!/usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
import io
import sys
import codecs
if sys.stdout.encoding != "UTF-8":
sys.stdout = codecs.getwriter("utf-8")(sys.stdout, "strict")
if sys.stderr.encoding != "UTF-8":
sys.stderr = codecs.getwriter("utf-8")(sys.stderr, "strict")
import os
import sys
import argparse
from OpenDirectory import ODSession, ODNode, ODQuery, kODRecordTypeUsers, kODAttributeTypeRecordName, kODAttributeTypeStandardOnly, kODMatchEqualTo, kODRecordTypeUsers
def main(argv):
p = argparse.ArgumentParser()
p.add_argument("username")
args = p.parse_args([x.decode("utf-8") for x in argv[1:]])
username = args.username
node, error = ODNode.nodeWithSession_name_error_(ODSession.defaultSession(), "/Local/Default", None)
if not node:
print("Couldn't open local node: {}".format(error.localizedDescription()))
return os.EX_UNAVAILABLE
query, error = ODQuery.queryWithNode_forRecordTypes_attribute_matchType_queryValues_returnAttributes_maximumResults_error_(node, kODRecordTypeUsers, kODAttributeTypeRecordName, kODMatchEqualTo, username, kODAttributeTypeStandardOnly, 0, None)
if not query:
print("Couldn't query local node: {}".format(error.localizedDescription()))
return os.EX_UNAVAILABLE
result, error = query.resultsAllowingPartial_error_(False, None)
if not result:
print("Couldn't find user: {}".format(error.localizedDescription()))
return os.EX_UNAVAILABLE
userrecord = result[0]
authauth = userrecord.valuesForAttribute_error_("dsAttrTypeStandard:AuthenticationAuthority", None)[0].mutableCopy()
if not authauth.containsObject_("'"):
print("{} looks fine".format(username))
return 0
print("Fixing AuthenticationAuthority for {}".format(username))
authauth.removeObject_("'")
for i in xrange(authauth.count()):
if authauth[i].endswith("'"):
fixed = authauth[i].substringToIndex_(authauth[i].length() - 1)
authauth.replaceObjectAtIndex_withObject_(i, fixed)
result, error = userrecord.setValue_forAttribute_error_(authauth, "dsAttrTypeStandard:AuthenticationAuthority", None)
if not result:
print("Couldn't set attribute: {}".format(error.localizedDescription()))
return os.EX_UNAVAILABLE
print("Fixed AuthenticationAuthority for {}".format(username))
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv))
#!/bin/bash
allgood="true"
result=""
while read -r user; do
authauth=$(dscl . -read /Users/"$user" AuthenticationAuthority)
if [[ "$authauth" == *\'* ]]; then
allgood="false"
result="$result bad:$user"
else
result="$result good:$user"
fi
done < <(dscl . -list /Users | egrep -v '^_')
if [[ "$allgood" == "true" ]]; then
result="All good"
fi
echo "<result>${result# }</result>"
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Check that the Authentication Authority of migrated AD accounts is good.
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
import io
import sys
import codecs
if sys.stdout.encoding != "UTF-8":
sys.stdout = codecs.getwriter("utf-8")(sys.stdout, "strict")
if sys.stderr.encoding != "UTF-8":
sys.stderr = codecs.getwriter("utf-8")(sys.stderr, "strict")
import plistlib
import os
from Foundation import CFPreferencesCopyAppValue
import subprocess
def dscl(args):
cmd = ["/usr/bin/dscl", "."] + args
return subprocess.check_output(cmd)
def list_users():
users = []
out = dscl(["-list", "/Users"])
for username in out.splitlines():
if username.startswith("_"):
continue
users.append(username)
return users
def read_authauth(username):
return dscl(["-read",
"/Users/{}".format(username),
"AuthenticationAuthority"])
def main(argv):
managedinstalldir = CFPreferencesCopyAppValue("ManagedInstallDir", "ManagedInstalls")
plist_path = os.path.join(managedinstalldir, "ConditionalItems.plist")
try:
conditions = plistlib.readPlist(plist_path)
except IOError:
conditions = {}
try:
result = []
all_good = True
for username in list_users():
if "'" in read_authauth(username):
all_good = False
result.append("bad:{}".format(username))
else:
result.append("good:{}".format(username))
if all_good:
conditions["authauth"] = "All good"
else:
conditions["authauth"] = " ".join(result)
except (IndexError, AttributeError):
return os.EX_SOFTWARE
except subprocess.CalledProcessError as e:
print("{}".format(e), file=sys.stderr)
return os.EX_UNAVAILABLE
plistlib.writePlist(conditions, plist_path)
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment