Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
GraceDB Server
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Container Registry
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
IGWN Computing and Software
GraceDB
GraceDB Server
Commits
ef5a108b
Commit
ef5a108b
authored
5 years ago
by
Tanner Prestegard
Committed by
GraceDB
5 years ago
Browse files
Options
Downloads
Patches
Plain Diff
Update user account "update from LDAP" script
Needs to work properly with new AuthGroup setup and X509Cert model changes
parent
2aad606e
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
gracedb/ligoauth/management/commands/update_user_accounts_from_ligo_ldap.py
+369
-147
369 additions, 147 deletions
...anagement/commands/update_user_accounts_from_ligo_ldap.py
with
369 additions
and
147 deletions
gracedb/ligoauth/management/commands/update_user_accounts_from_ligo_ldap.py
+
369
−
147
View file @
ef5a108b
...
...
@@ -2,169 +2,391 @@ import datetime
import
ldap
from
django.conf
import
settings
from
django.contrib.auth
.models
import
User
from
django.contrib.auth
import
get_user_model
from
django.core.management.base
import
BaseCommand
,
CommandError
from
ligoauth.models
import
LigoLdapUser
,
X509Cert
,
AuthGroup
UserModel
=
get_user_model
()
# Classes for processing LDAP results into user accounts ----------------------
class
LdapPersonResultProcessor
(
object
):
stdout
=
None
def
__init__
(
self
,
ldap_dn
,
ldap_result
,
ldap_connection
=
None
,
verbose
=
True
,
stdout
=
None
,
*
args
,
**
kwargs
):
super
(
LdapPersonResultProcessor
,
self
).
__init__
(
*
args
,
**
kwargs
)
self
.
ldap_dn
=
ldap_dn
self
.
ldap_result
=
ldap_result
self
.
verbose
=
verbose
self
.
ldap_connection
=
ldap_connection
self
.
stdout
=
stdout
def
write
(
self
,
message
):
if
self
.
stdout
:
self
.
stdout
.
write
(
message
)
else
:
print
(
message
)
def
extract_user_attributes
(
self
):
if
self
.
ldap_connection
is
None
:
raise
RuntimeError
(
'
LDAP connection not configured
'
)
self
.
user_data
=
{
'
first_name
'
:
unicode
(
self
.
ldap_result
[
'
givenName
'
][
0
],
'
utf-8
'
),
'
last_name
'
:
unicode
(
self
.
ldap_result
[
'
sn
'
][
0
],
'
utf-8
'
),
'
email
'
:
self
.
ldap_result
[
'
mail
'
][
0
],
'
is_active
'
:
self
.
ldap_connection
.
lvc_group
.
ldap_name
in
self
.
ldap_result
.
get
(
'
isMemberOf
'
,
[]),
'
username
'
:
self
.
ldap_result
[
'
krbPrincipalName
'
][
0
],
}
def
check_situation
(
self
,
user_exists
,
l_user_exists
):
pass
def
get_or_create_user
(
self
):
if
not
hasattr
(
self
,
'
user_data
'
):
self
.
extract_user_attributes
()
# Determine if users exist
user_exists
=
UserModel
.
objects
.
filter
(
username
=
self
.
user_data
[
'
username
'
]).
exists
()
l_user_exists
=
LigoLdapUser
.
objects
.
filter
(
ldap_dn
=
self
.
ldap_dn
).
exists
()
# Run any necessary checks at this point
self
.
check_situation
(
user_exists
,
l_user_exists
)
# Handle different cases
self
.
user_created
=
False
if
l_user_exists
:
# LigoLdapUser exists already (and thus, User object exists too)
l_user
=
LigoLdapUser
.
objects
.
get
(
ldap_dn
=
self
.
ldap_dn
)
user
=
l_user
.
user_ptr
else
:
# LigoLdapUser doesn't exist
if
user_exists
:
# User object exists, though, so we have to carefully create
# the LigoLdapUser object
user
=
UserModel
.
objects
.
get
(
username
=
self
.
user_data
[
'
username
'
])
l_user
=
LigoLdapUser
(
ldap_dn
=
self
.
ldap_dn
,
user_ptr
=
user
)
l_user
.
__dict__
.
update
(
user
.
__dict__
)
l_user
.
save
()
if
self
.
verbose
:
self
.
write
(
"
Created ligoldapuser for {0}
"
.
format
(
user
.
username
))
else
:
# No User object either, so we do a simple creation
l_user
=
LigoLdapUser
.
objects
.
create
(
ldap_dn
=
self
.
ldap_dn
,
**
self
.
user_data
)
user
=
l_user
.
user_ptr
if
self
.
verbose
:
self
.
write
(
"
Created user and ligoldapuser for {0}
"
.
format
(
l_user
.
username
))
self
.
user_created
=
True
self
.
ligoldapuser
=
l_user
self
.
user
=
user
self
.
check_user_accounts
()
def
check_user_accounts
(
self
):
if
not
(
hasattr
(
self
,
'
user_data
'
)
or
hasattr
(
self
,
'
user
'
)):
raise
RuntimeError
(
'
User data or user object missing
'
)
if
(
self
.
user
.
username
!=
self
.
user_data
[
'
username
'
]
and
self
.
user_exists
):
self
.
write
((
'
ERROR: requires manual investigation. LDAP
'
'
username: {0}, ligoldapuser.user_ptr.username: {1}
'
)
.
format
(
self
.
user_data
[
'
username
'
],
self
.
ligoldapuser
.
user_ptr
.
username
))
raise
UserConfigError
(
'
User configuration error
'
)
def
update_user
(
self
):
if
not
hasattr
(
self
,
'
user
'
):
raise
RuntimeError
(
'
User object missing
'
)
self
.
update_user_attributes
()
self
.
update_user_groups
()
self
.
update_user_certificates
()
def
get_attributes_to_update
(
self
):
attributes_to_update
=
[
k
for
k
,
v
in
self
.
user_data
.
items
()
if
v
!=
getattr
(
self
.
ligoldapuser
,
k
)]
return
attributes_to_update
def
update_user_attributes
(
self
):
self
.
user_changed
=
False
# Don't do anything if the user was just created
if
self
.
user_created
:
return
# Update attributes
attributes_to_update
=
self
.
get_attributes_to_update
()
if
attributes_to_update
:
self
.
user_changed
=
True
for
k
in
attributes_to_update
:
setattr
(
self
.
ligoldapuser
,
k
,
self
.
user_data
[
k
])
# Revoke staff/superuser if not active.
if
((
self
.
ligoldapuser
.
is_staff
or
self
.
ligoldapuser
.
is_superuser
)
and
not
self
.
user_data
[
'
is_active
'
]):
self
.
ligoldapuser
.
is_staff
=
self
.
ligoldapuser
.
is_superuser
=
False
self
.
user_changed
=
True
if
self
.
user_changed
and
self
.
verbose
:
self
.
write
(
"
User {0} updated
"
.
format
(
self
.
ligoldapuser
.
username
))
def
update_user_groups
(
self
):
# Get list of group names that the user belongs to from the LDAP result
memberships
=
self
.
ldap_result
.
get
(
'
isMemberOf
'
,
[])
# Get groups which are listed for the user in the LDAP and whose
# membership is controlled by the LDAP
ldap_groups_to_add
=
self
.
ldap_connection
.
groups
.
filter
(
ldap_name__in
=
memberships
).
exclude
(
pk__in
=
self
.
ligoldapuser
.
groups
.
all
())
# Add the user to these groups
if
self
.
verbose
and
ldap_groups_to_add
.
exists
():
self
.
write
(
"
Adding {0} to {1}
"
.
format
(
self
.
ligoldapuser
.
username
,
"
and
"
.
join
(
list
(
ldap_groups_to_add
.
values_list
(
'
name
'
,
flat
=
True
)))))
self
.
ligoldapuser
.
groups
.
add
(
*
ldap_groups_to_add
)
# Get groups which are *not* listed for the user in the LDAP and whose
# membership is controlled by the LDAP
ldap_groups_to_remove
=
self
.
ligoldapuser
.
groups
.
filter
(
pk__in
=
self
.
ldap_connection
.
groups
.
exclude
(
ldap_name__in
=
memberships
))
# Remove the user from these groups
if
self
.
verbose
and
ldap_groups_to_remove
.
exists
():
self
.
write
(
"
Removing {0} from {1}
"
.
format
(
self
.
ligoldapuser
.
username
,
"
and
"
.
join
(
list
(
ldap_groups_to_remove
.
values_list
(
'
name
'
,
flat
=
True
)))))
self
.
ligoldapuser
.
groups
.
remove
(
*
ldap_groups_to_remove
)
def
add_certs
(
self
,
certs
):
# Add new certificates to user
for
subject
in
certs
:
if
self
.
verbose
:
self
.
write
(
'
Creating certificate with subject {0} for {1}
'
.
format
(
subject
,
self
.
ligoldapuser
.
username
))
cert
,
_
=
X509Cert
.
objects
.
get_or_create
(
subject
=
subject
,
user
=
self
.
ligoldapuser
)
def
remove_certs
(
self
,
certs
):
# Remove old certificates from user
# NOTE: we just delete these certs. They will be created again
# if another user adds them. This helps to keep random certificates
# from floating around without a user.
for
subject
in
certs
:
if
self
.
verbose
:
self
.
write
(
'
Deleting certificate with subject {0} for {1}
'
.
format
(
subject
,
self
.
ligoldapuser
.
username
))
cert
=
self
.
ligoldapuser
.
x509cert_set
.
get
(
subject
=
subject
)
cert
.
delete
()
def
update_user_certificates
(
self
):
# Get two lists of subjects as sets
db_x509_subjects
=
set
(
list
(
self
.
ligoldapuser
.
x509cert_set
.
values_list
(
'
subject
'
,
flat
=
True
)))
ldap_x509_subjects
=
set
(
self
.
ldap_result
.
get
(
'
gridX509subject
'
,
[]))
# Get certs to add and remove
certs_to_add
=
ldap_x509_subjects
.
difference
(
db_x509_subjects
)
certs_to_remove
=
db_x509_subjects
.
difference
(
ldap_x509_subjects
)
# Add and remove certificates
self
.
add_certs
(
certs_to_add
)
self
.
remove_certs
(
certs_to_remove
)
def
save_user
(
self
):
if
self
.
user_created
or
self
.
user_changed
:
try
:
self
.
ligoldapuser
.
save
()
except
Exception
as
e
:
self
.
write
(
"
Failed to save user
'
{0}
'
: {1}.
"
.
format
(
self
.
ligoldapuser
.
username
,
e
))
class
UserConfigError
(
Exception
):
pass
class
UnacceptableUserError
(
Exception
):
pass
class
LdapRobotResultProcessor
(
LdapPersonResultProcessor
):
def
extract_user_attributes
(
self
):
if
self
.
ldap_connection
is
None
:
raise
RuntimeError
(
'
LDAP connection not configured
'
)
self
.
user_data
=
{
'
last_name
'
:
unicode
(
self
.
ldap_result
[
'
x-LIGO-TWikiName
'
][
0
],
'
utf-8
'
),
'
email
'
:
self
.
ldap_result
[
'
mail
'
][
0
],
'
is_active
'
:
self
.
ldap_connection
.
groups
.
get
(
name
=
'
robot_accounts
'
).
name
in
self
.
ldap_result
.
get
(
'
isMemberOf
'
,
[]),
'
username
'
:
self
.
ldap_result
[
'
cn
'
][
0
],
}
def
check_situation
(
self
,
user_exists
,
l_user_exists
):
if
(
not
(
user_exists
or
l_user_exists
)
and
not
self
.
user_data
[
'
is_active
'
]):
err_msg
=
'
User {0} should not be added to the DB
'
.
format
(
self
.
user_data
[
'
username
'
])
self
.
write
(
err_msg
)
raise
self
.
UnacceptableUserError
(
err_msg
)
def
get_attributes_to_update
(
self
):
attributes_to_update
=
[
k
for
k
in
[
'
email
'
,
'
is_active
'
]
if
self
.
user_data
[
k
]
!=
getattr
(
self
.
ligoldapuser
,
k
)]
return
attributes_to_update
def
remove_certs
(
self
,
certs
):
pass
# NOTE: for now (2019) we don't remove any robot certificates since
# there arestill some old LIGO CA certificates in use that aren't in
# the LDAP
# Classes for handling LDAP connections and queries ---------------------------
class
LigoPeopleLdap
(
object
):
name
=
'
people
'
ldap_host
=
"
ldaps://ldap.ligo.org
"
ldap_port
=
636
ldap_protocol_version
=
ldap
.
VERSION3
base_dn
=
"
ou=people,dc=ligo,dc=org
"
search_filter
=
"
(employeeNumber=*)
"
search_scope
=
ldap
.
SCOPE_SUBTREE
attribute_list
=
[
"
krbPrincipalName
"
,
"
gridX509subject
"
,
"
givenName
"
,
"
sn
"
,
"
mail
"
,
"
isMemberOf
"
,
]
group_names
=
[
'
internal_users
'
,
'
em_advocates
'
]
user_processor_class
=
LdapPersonResultProcessor
def
__init__
(
self
,
verbose
=
True
,
*
args
,
**
kwargs
):
super
(
LigoPeopleLdap
,
self
).
__init__
(
*
args
,
**
kwargs
)
# Check configuration
if
not
self
.
base_dn
:
raise
ValueError
(
'
self.base_dn must be set
'
)
#if not self.attribute_list:
# raise ValueError('self.attribute_list must be set')
# Set up groups
self
.
groups
=
AuthGroup
.
objects
.
filter
(
name__in
=
self
.
group_names
)
self
.
lvc_group
=
AuthGroup
.
objects
.
get
(
name
=
settings
.
LVC_GROUP
)
self
.
verbose
=
verbose
def
initialize
(
self
):
ldap_address
=
'
{host}:{port}
'
.
format
(
host
=
self
.
ldap_host
,
port
=
self
.
ldap_port
)
self
.
ldap_object
=
ldap
.
initialize
(
ldap_address
)
self
.
ldap_object
.
protocol_version
=
self
.
ldap_protocol_version
def
initialize_user_processor
(
self
,
*
args
,
**
kwargs
):
self
.
user_processor
=
self
.
user_processor_class
(
*
args
,
**
kwargs
)
self
.
user_processor
.
ldap_connection
=
self
return
self
.
user_processor
def
perform_query
(
self
):
ldap_result_id
=
self
.
ldap_object
.
search
(
self
.
base_dn
,
self
.
search_scope
,
filterstr
=
self
.
search_filter
,
attrlist
=
self
.
attribute_list
)
result_type
,
result_data
=
self
.
ldap_object
.
result
(
ldap_result_id
,
all
=
1
,
timeout
=
30
)
if
not
result_type
==
ldap
.
RES_SEARCH_RESULT
:
err_msg
=
'
Unexpected result type ({rt}) from LDAP query
'
.
format
(
rt
=
result_type
)
raise
TypeError
(
err_msg
)
return
result_data
class
LigoRobotsLdap
(
LigoPeopleLdap
):
name
=
'
robots
'
base_dn
=
"
ou=keytab,ou=robot,dc=ligo,dc=org
"
search_filter
=
"
(cn=*)
"
search_scope
=
ldap
.
SCOPE_SUBTREE
attribute_list
=
[
'
cn
'
,
'
uid
'
,
'
gridX509subject
'
,
'
mail
'
,
'
isMemberOf
'
,
'
x-LIGO-TWikiName
'
,
]
group_names
=
[
'
internal_users
'
,
'
robot_accounts
'
]
user_processor_class
=
LdapRobotResultProcessor
# Dict of LDAP classes with names as keys
# NOTE: not using robot OU right now since we are waiting
# for some auth infrastructure changes to be able to properly group
# certificates into a user account
#LDAP_CLASSES = {l.name: l for l in (LigoPeopleLdap, LigoRobotsLdap)}
LDAP_CLASSES
=
{
l
.
name
:
l
for
l
in
(
LigoPeopleLdap
,)}
# Variables for LDAP search
BASE_DN
=
"
ou=people,dc=ligo,dc=org
"
SEARCH_SCOPE
=
ldap
.
SCOPE_SUBTREE
SEARCH_FILTER
=
"
(employeeNumber=*)
"
RETRIEVE_ATTRIBUTES
=
[
"
krbPrincipalName
"
,
"
gridX509subject
"
,
"
givenName
"
,
"
sn
"
,
"
mail
"
,
"
isMemberOf
"
,
]
LDAP_ADDRESS
=
"
ldap.ligo.org
"
LDAP_PORT
=
636
class
Command
(
BaseCommand
):
help
=
"
Get updated user data from LIGO LDAP
"
def
add_arguments
(
self
,
parser
):
parser
.
add_argument
(
'
ldap
'
,
choices
=
list
(
LDAP_CLASSES
),
help
=
"
Name of LDAP to use
"
)
parser
.
add_argument
(
'
-q
'
,
'
--quiet
'
,
action
=
'
store_true
'
,
default
=
False
,
help
=
'
Suppress output
'
)
def
handle
(
self
,
*
args
,
**
options
):
if
options
[
'
ldap
'
]
==
'
robots
'
:
raise
ValueError
(
'
Not properly set up for robot OU
'
)
verbose
=
not
options
[
'
quiet
'
]
if
verbose
:
self
.
stdout
.
write
(
'
Refreshing users from LIGO LDAP at {0}
'
\
.
format
(
datetime
.
datetime
.
utcnow
()))
# Get LVC group
lvc_group
=
Group
.
objects
.
get
(
name
=
settings
.
LVC_GROUP
)
# Open connection to LDAP and run a search
l
=
ldap
.
initialize
(
"
ldaps://{address}:{port}
"
.
format
(
address
=
LDAP_ADDRESS
,
port
=
LDAP_PORT
))
l
.
protocol_version
=
ldap
.
VERSION3
ldap_result_id
=
l
.
search
(
BASE_DN
,
SEARCH_SCOPE
,
SEARCH_FILTER
,
RETRIEVE_ATTRIBUTES
)
# Get all results
result_data
=
True
while
result_data
:
result_type
,
result_data
=
l
.
result
(
ldap_result_id
,
0
)
if
result_type
==
ldap
.
RES_SEARCH_ENTRY
:
for
(
ldap_dn
,
ldap_result
)
in
result_data
:
first_name
=
unicode
(
ldap_result
[
'
givenName
'
][
0
],
'
utf-8
'
)
last_name
=
unicode
(
ldap_result
[
'
sn
'
][
0
],
'
utf-8
'
)
email
=
ldap_result
[
'
mail
'
][
0
]
new_dns
=
set
(
ldap_result
.
get
(
'
gridX509subject
'
,
[]))
memberships
=
ldap_result
.
get
(
'
isMemberOf
'
,
[])
is_active
=
lvc_group
.
name
in
memberships
principal
=
ldap_result
[
'
krbPrincipalName
'
][
0
]
# Update/Create LigoLdapUser entry
defaults
=
{
'
first_name
'
:
first_name
,
'
last_name
'
:
last_name
,
'
email
'
:
email
,
'
username
'
:
principal
,
'
is_active
'
:
is_active
,
}
# Determine if base user and ligoldapuser objects exist
user_exists
=
User
.
objects
.
filter
(
username
=
defaults
[
'
username
'
]).
exists
()
l_user_exists
=
LigoLdapUser
.
objects
.
filter
(
ldap_dn
=
ldap_dn
).
exists
()
# Handle different cases
created
=
False
if
l_user_exists
:
l_user
=
LigoLdapUser
.
objects
.
get
(
ldap_dn
=
ldap_dn
)
user
=
l_user
.
user_ptr
else
:
if
user_exists
:
user
=
User
.
objects
.
get
(
username
=
defaults
[
'
username
'
])
l_user
=
LigoLdapUser
.
objects
.
create
(
ldap_dn
=
ldap_dn
,
user_ptr
=
user
)
l_user
.
__dict__
.
update
(
user
.
__dict__
)
if
verbose
:
self
.
stdout
.
write
((
"
Created ligoldapuser
"
"
for {0}
"
).
format
(
user
.
username
))
else
:
l_user
=
LigoLdapUser
.
objects
.
create
(
ldap_dn
=
ldap_dn
,
**
defaults
)
user
=
l_user
.
user_ptr
if
verbose
:
self
.
stdout
.
write
((
"
Created user and
"
"
ligoldapuser for {0}
"
).
format
(
l_user
.
username
))
created
=
True
# Typically a case where the person's username was changed
# and there are now two user accounts in GraceDB
if
user
.
username
!=
defaults
[
'
username
'
]
and
user_exists
:
self
.
stdout
.
write
((
'
ERROR: requires manual
'
'
investigation. LDAP username: {0},
'
'
ligoldapuser.user_ptr.username: {1}
'
).
format
(
defaults
[
'
username
'
],
l_user
.
user_ptr
.
username
))
continue
# Update user attributes from LDAP
changed
=
False
if
not
created
:
for
k
in
defaults
:
if
(
defaults
[
k
]
!=
getattr
(
user
,
k
)):
setattr
(
l_user
,
k
,
defaults
[
k
])
changed
=
True
if
changed
and
verbose
:
self
.
stdout
.
write
(
"
User {0} updated
"
.
format
(
l_user
.
username
))
# Revoke staff/superuser if not active.
if
((
l_user
.
is_staff
or
l_user
.
is_superuser
)
and
not
is_active
):
l_user
.
is_staff
=
l_user
.
is_superuser
=
False
changed
=
True
# Try to save user.
if
created
or
changed
:
try
:
l_user
.
save
()
except
Exception
as
e
:
self
.
stdout
.
write
((
"
Failed to save user
'
{0}
'
:
"
"
{1}.
"
).
format
(
l_user
.
username
,
e
))
continue
# Update X509 certs for user
current_dns
=
set
([
c
.
subject
for
c
in
user
.
x509cert_set
.
all
()])
if
current_dns
!=
new_dns
:
for
dn
in
new_dns
-
current_dns
:
cert
,
created
=
X509Cert
.
objects
.
get_or_create
(
subject
=
dn
)
cert
.
users
.
add
(
l_user
)
# Update group information - we do this only for groups
# that already exist in GraceDB
for
g
in
Group
.
objects
.
all
():
# Add the user to the group if they aren't a member
if
(
g
.
name
in
memberships
and
g
not
in
l_user
.
groups
.
all
()):
g
.
user_set
.
add
(
l_user
)
if
verbose
:
self
.
stdout
.
write
(
"
Adding {0} to {1}
"
.
format
(
l_user
.
username
,
g
.
name
))
# Remove the user from the LVC group if they are no longer
# a member. This is the only group in GraceDB which is
# populated from the LIGO LDAP.
if
(
lvc_group
.
name
not
in
memberships
and
lvc_group
in
l_user
.
groups
.
all
()):
l_user
.
groups
.
remove
(
lvc_group
)
if
verbose
:
self
.
stdout
.
write
(
"
Removing {user} from {group}
"
\
.
format
(
user
=
l_user
.
username
,
group
=
lvc_group
.
name
))
# Set up ldap connection
ldap_connection
=
LDAP_CLASSES
[
options
[
'
ldap
'
]](
verbose
=
verbose
)
ldap_connection
.
initialize
()
# Perform query and get all results
result_data
=
ldap_connection
.
perform_query
()
# Loop over results
for
ldap_dn
,
ldap_result
in
result_data
:
# Set up user processor
user_processor
=
ldap_connection
.
initialize_user_processor
(
ldap_dn
,
ldap_result
,
verbose
=
verbose
,
stdout
=
self
.
stdout
)
# Get or create user - if an error occurs, continue.
# Details should already be written to the log.
try
:
user_processor
.
extract_user_attributes
()
user_processor
.
get_or_create_user
()
except
user_processor
.
UserConfigError
as
e
:
continue
except
user_processor
.
UnacceptableUserError
as
e
:
# Indicates that the user shouldn't be added
continue
# Update user based on LDAP information - this includes
# attributes, group memberships, X509 certificates, etc.
user_processor
.
update_user
()
# Try to save user
user_processor
.
save_user
()
# Extra stuff
if
(
ldap_connection
.
name
==
'
robots
'
):
pass
# NOTE: eventually (i.e., once all of the old LIGO.ORG certificates
# are expired), we will want to remove any robot certificates which
# aren't found in this LDAP query (effectively deactivating any
# accounts which have no certificates attached to them).
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment