Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
U
uffd
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
rixx
uffd
Commits
bb9c49cc
Commit
bb9c49cc
authored
4 years ago
by
Julian
Browse files
Options
Downloads
Patches
Plain Diff
Rewrote everything
parent
19a484ff
No related branches found
No related tags found
No related merge requests found
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
ldap3_mapper_new/base.py
+134
-164
134 additions, 164 deletions
ldap3_mapper_new/base.py
with
134 additions
and
164 deletions
ldap3_mapper_new/base.py
+
134
−
164
View file @
bb9c49cc
from
enum
import
Enum
from
copy
import
deepcopy
from
copy
import
deepcopy
class
S
tatus
(
Enum
)
:
class
S
essionState
:
NEW
def
__init__
(
self
,
objects
=
None
,
deleted_objects
=
None
):
ADDED
self
.
objects
=
objects
or
{}
DELETED
self
.
deleted_objects
=
deleted_objects
or
{}
class
State
:
def
copy
(
self
):
def
__init__
(
self
,
status
=
Status
.
NEW
,
attributes
=
None
):
return
SessionState
(
objects
=
deepcopy
(
self
.
objects
),
deleted_objects
=
deepcopy
(
self
.
deleted_objects
))
self
.
status
=
status
class
ObjectState
:
def
__init__
(
self
,
session
=
None
,
attributes
=
None
,
dn
=
None
):
self
.
session
=
session
self
.
attributes
=
attributes
or
{}
self
.
attributes
=
attributes
or
{}
self
.
dn
=
dn
def
copy
(
self
):
def
copy
(
self
):
return
State
(
self
.
status
,
deepcopy
(
self
.
attributes
))
return
ObjectState
(
attributes
=
deepcopy
(
self
.
attributes
)
,
dn
=
self
.
dn
,
session
=
self
.
session
)
class
Operation
:
class
Add
Operation
:
def
__init__
(
self
,
obj
):
def
__init__
(
self
,
obj
,
dn
,
object_classes
):
self
.
obj
=
obj
self
.
obj
=
obj
self
.
dn
=
dn
self
.
object_classes
=
object_classes
self
.
attributes
=
deepcopy
(
obj
.
state
.
attributes
)
def
apply
(
self
,
state
):
def
apply_object
(
self
,
obj_state
):
raise
NotImplemented
()
obj_state
.
dn
=
self
.
dn
obj_state
.
attributes
=
deepcopy
(
self
.
attributes
)
def
execute
(
self
,
conn
):
def
apply_session
(
self
,
session_state
):
raise
NotImplemented
()
assert
self
.
dn
not
in
session_state
.
objects
session_state
.
objects
[
self
.
dn
]
=
self
.
obj
def
extend
(
self
,
oper
):
def
apply_ldap
(
self
,
conn
):
return
False
success
=
conn
.
add
(
self
.
dn
,
self
.
object_classes
,
self
.
attributes
)
class
AddOperation
(
Operation
):
def
__init__
(
self
,
obj
,
attributes
,
ldap_object_classes
):
super
().
__init__
(
obj
)
self
.
attributes
=
deepcopy
(
attributes
)
self
.
ldap_object_classes
=
ldap_object_classes
def
apply
(
self
,
state
):
state
.
status
=
Status
.
ADDED
state
.
attributes
=
self
.
attributes
def
execute
(
self
,
conn
):
success
=
conn
.
add
(
self
.
obj
.
dn
,
self
.
ldap_object_classes
,
self
.
attributes
)
if
not
success
:
if
not
success
:
raise
LDAPCommitError
()
raise
LDAPCommitError
()
class
DeleteOperation
(
Operation
):
class
DeleteOperation
:
def
apply
(
self
,
state
):
def
__init__
(
self
,
obj
):
state
.
status
=
Status
.
DELETED
self
.
dn
=
obj
.
state
.
dn
self
.
obj
=
obj
def
apply_object
(
self
,
obj_state
):
obj_state
.
dn
=
None
def
execute
(
self
,
conn
):
def
apply_session
(
self
,
session_state
):
success
=
conn
.
delete
(
self
.
obj
.
dn
)
assert
self
.
dn
in
session_state
.
objects
del
session_state
.
objects
[
self
.
dn
]
session_state
.
deleted_objects
[
self
.
dn
]
=
self
.
obj
def
apply_ldap
(
self
,
conn
):
success
=
conn
.
delete
(
self
.
dn
)
if
not
success
:
if
not
success
:
raise
LDAPCommitError
()
raise
LDAPCommitError
()
class
ModifyOperation
(
Operation
)
:
class
ModifyOperation
:
def
__init__
(
self
,
obj
,
changes
):
def
__init__
(
self
,
obj
,
changes
):
s
uper
().
__init__
(
obj
)
s
elf
.
obj
=
obj
self
.
changes
=
deepcopy
(
changes
)
self
.
changes
=
deepcopy
(
changes
)
def
apply
(
self
,
state
):
def
apply
_object
(
self
,
obj_
state
):
for
attr
,
changes
in
self
.
changes
.
items
():
for
attr
,
changes
in
self
.
changes
.
items
():
for
action
,
values
in
changes
:
for
action
,
values
in
changes
:
if
action
==
MODIFY_REPLACE
:
if
action
==
MODIFY_REPLACE
:
state
.
attributes
[
attr
]
=
values
obj_
state
.
attributes
[
attr
]
=
values
elif
action
==
MODIFY_ADD
:
elif
action
==
MODIFY_ADD
:
state
.
attributes
[
attr
]
+=
values
obj_
state
.
attributes
[
attr
]
+=
values
elif
action
==
MODIFY_DELETE
:
elif
action
==
MODIFY_DELETE
:
for
value
in
values
:
for
value
in
values
:
state
.
attributes
[
attr
].
remove
(
value
)
obj_
state
.
attributes
[
attr
].
remove
(
value
)
def
execute
(
self
,
conn
):
def
apply_session
(
self
,
session_state
):
success
=
conn
.
modify
(
self
.
obj
.
dn
,
self
.
changes
)
pass
def
apply_ldap
(
self
,
conn
):
success
=
conn
.
modify
(
self
.
obj
.
state
.
dn
,
self
.
changes
)
if
not
success
:
if
not
success
:
raise
LDAPCommitError
()
raise
LDAPCommitError
()
class
Session
:
class
Session
:
ldap_mapper
=
None
def
__init__
(
self
,
get_connection
):
self
.
get_connection
=
get_connection
def
__init__
(
self
):
self
.
committed_state
=
SessionState
()
self
.
__objects
=
{}
self
.
state
=
SessionState
()
self
.
__deleted_objects
=
{}
self
.
changes
=
[]
self
.
__operations
=
[]
def
add
(
self
,
obj
,
dn
,
object_classes
):
# Never called directly!
if
self
.
state
.
objects
.
get
(
dn
)
==
obj
:
def
record
(
self
,
oper
):
if
isinstance
(
oper
,
AddOperation
):
if
oper
.
obj
.
ldap_state
.
session
==
self
:
return
return
if
oper
.
obj
.
ldap_state
.
session
is
not
None
:
assert
obj
.
state
.
session
is
None
raise
Exception
()
oper
=
AddOperation
(
obj
,
dn
,
object_classes
)
if
oper
.
obj
.
dn
in
self
.
__objects
:
oper
.
apply_object
(
obj
.
state
)
raise
Exception
()
oper
.
apply_session
(
self
.
state
)
self
.
__objects
[
oper
.
obj
.
dn
]
=
oper
.
obj
self
.
changes
.
append
(
oper
)
elif
isinstance
(
oper
,
DeleteOperation
):
if
oper
.
obj
.
ldap_state
.
session
is
None
:
return
if
oper
.
obj
.
ldap_state
.
session
!=
self
:
raise
Exception
()
if
oper
.
obj
.
dn
not
in
self
.
__objects
:
raise
Exception
()
if
oper
.
obj
.
dn
in
self
.
__deleted_objects
:
raise
Exception
()
self
.
__deleted_objects
[
oper
.
obj
.
dn
]
=
oper
.
obj
del
self
.
__objects
[
oper
.
obj
.
dn
]
else
:
if
oper
.
obj
.
ldap_state
.
session
is
None
:
return
if
not
self
.
__operations
or
not
self
.
__operations
[
-
1
].
extend
(
oper
):
self
.
__operations
.
append
(
oper
)
def
add
(
self
,
obj
):
obj
.
ldap_state
.
add
(
self
)
def
delete
(
self
,
obj
):
def
delete
(
self
,
obj
):
obj
.
ldap_state
.
delete
()
if
obj
.
state
.
dn
not
in
self
.
state
.
objects
:
return
assert
obj
.
state
.
session
==
self
oper
=
DeleteOperation
(
obj
)
oper
.
apply_object
(
obj
.
state
)
obj
.
state
.
session
=
None
oper
.
apply_session
(
self
.
state
)
self
.
changes
.
append
(
oper
)
def
record
(
self
,
oper
):
assert
oper
.
obj
.
state
.
session
==
self
self
.
changes
.
append
(
oper
)
def
commit
(
self
):
def
commit
(
self
):
conn
=
self
.
mapper
.
connect
()
conn
=
self
.
get_
connect
ion
()
while
self
.
__operation
s
:
while
self
.
change
s
:
obj
,
oper
=
self
.
__operation
s
.
pop
(
0
)
oper
=
self
.
change
s
.
pop
(
0
)
try
:
try
:
oper
.
execute
(
obj
.
dn
,
conn
)
oper
.
apply_ldap
(
conn
)
except
e
:
except
e
:
self
.
__operation
s
.
insert
(
0
,
(
obj
,
oper
)
)
self
.
change
s
.
insert
(
0
,
oper
)
raise
e
raise
e
oper
.
apply_object
(
oper
.
obj
.
committed_state
)
oper
.
apply_session
(
self
.
committed_state
)
self
.
committed_state
=
self
.
state
.
copy
()
def
rollback
(
self
):
def
rollback
(
self
):
while
self
.
__operations
:
for
obj
in
self
.
state
.
objects
.
values
():
obj
,
oper
=
self
.
__operations
.
pop
(
0
)
obj
.
state
=
obj
.
committed_state
.
copy
()
obj
.
ldap_state
.
current
=
obj
.
ldap_state
.
committed
.
copy
()
for
obj
in
self
.
state
.
deleted_objects
.
values
():
obj
.
state
=
obj
.
committed_state
.
copy
()
def
query_get
(
self
,
cls
,
dn
):
self
.
state
=
self
.
committed_state
.
copy
()
if
dn
in
self
.
__objects
:
self
.
changes
.
clear
()
return
self
.
__objects
[
dn
]
if
dn
in
self
.
__deleted_objects
:
def
get
(
self
,
dn
,
search_filter
):
if
dn
in
self
.
state
.
objects
:
return
self
.
state
.
objects
[
dn
]
if
dn
in
self
.
state
.
deleted_objects
:
return
None
return
None
conn
=
self
.
mapper
.
connect
()
conn
=
self
.
get_
connect
ion
()
conn
.
search
(
dn
,
cls
.
ldap
_filter
,
attributes
=
[
ALL_ATTRIBUTES
,
ALL_OPERATIONAL_ATTRIBUTES
])
conn
.
search
(
dn
,
search
_filter
,
attributes
=
[
ALL_ATTRIBUTES
,
ALL_OPERATIONAL_ATTRIBUTES
])
if
not
conn
.
response
:
if
not
conn
.
response
:
return
None
return
None
self
.
__objects
[
dn
]
=
cls
(
__ldap_response
=
conn
.
response
[
0
])
assert
len
(
conn
.
response
)
==
1
return
self
.
__objects
[
dn
]
assert
conn
.
response
[
0
][
'
dn
'
]
==
dn
self
.
state
.
objects
[
dn
]
=
Object
(
self
,
conn
.
response
[
0
])
def
query_search
(
self
,
cls
,
filters
=
None
):
self
.
committed_state
.
objects
[
dn
]
=
self
.
state
.
objects
[
dn
]
filters
=
[
cls
.
ldap_filter
]
+
(
filters
or
[])
return
self
.
state
.
objects
[
dn
]
if
len
(
filters
)
==
1
:
expr
=
filters
[
0
]
def
search
(
self
,
search_base
,
search_filter
):
else
:
conn
=
self
.
get_connection
()
expr
=
'
(&%s)
'
%
(
''
.
join
(
filters
))
conn
.
search
(
search_base
,
search_filter
,
attributes
=
[
ALL_ATTRIBUTES
,
ALL_OPERATIONAL_ATTRIBUTES
])
conn
=
self
.
mapper
.
connect
()
conn
.
search
(
cls
.
ldap_base
,
cls
.
ldap_filter
,
attributes
=
[
ALL_ATTRIBUTES
,
ALL_OPERATIONAL_ATTRIBUTES
])
res
=
[]
res
=
[]
for
response
in
conn
.
response
:
for
response
in
conn
.
response
:
dn
=
response
[
'
dn
'
]
dn
=
response
[
'
dn
'
]
if
dn
in
self
.
__
objects
:
if
dn
in
self
.
state
.
objects
:
res
.
append
(
self
.
__
objects
[
dn
])
res
.
append
(
self
.
state
.
objects
[
dn
])
elif
dn
in
self
.
__
deleted_objects
:
elif
dn
in
self
.
state
.
deleted_objects
:
continue
continue
else
:
else
:
self
.
__objects
[
dn
]
=
cls
(
__ldap_response
=
response
)
self
.
state
.
objects
[
dn
]
=
Object
(
self
,
response
)
res
.
append
(
self
.
__objects
[
dn
])
self
.
committed_state
.
objects
[
dn
]
=
self
.
state
.
objects
[
dn
]
res
.
append
(
self
.
state
.
objects
[
dn
])
return
res
return
res
# This is only a seperate class to keep SessionObject's namespace cleaner
class
Object
:
class
SessionObjectState
:
def
__init__
(
self
,
session
=
None
,
response
=
None
):
def
__init__
(
self
,
obj
,
response
=
None
):
if
response
is
None
:
self
.
obj
=
obj
self
.
committed_state
=
ObjectState
()
self
.
session
=
None
if
response
is
not
None
:
self
.
commited
=
State
()
else
:
else
:
self
.
commited
=
State
(
Status
.
ADDED
,
response
[
'
attributes
'
])
assert
session
is
not
None
self
.
current
=
self
.
commited
.
copy
()
self
.
committed_state
=
ObjectState
(
session
,
response
[
'
attributes
'
],
response
[
'
dn
'
])
self
.
state
=
self
.
committed_state
.
copy
()
def
add
(
self
,
session
):
if
self
.
session
is
not
None
:
return
# TODO: call hook functions
oper
=
AddOperation
(
self
.
current
.
attributes
,
self
.
obj
.
ldap_object_classes
)
self
.
session
.
record
(
self
.
obj
,
oper
)
self
.
session
=
session
oper
.
apply
(
self
.
current
)
def
delete
(
self
):
if
self
.
session
is
None
:
return
oper
=
DeleteOperation
()
self
.
session
.
record
(
self
.
obj
,
oper
)
self
.
session
=
None
oper
.
apply
(
self
.
current
)
def
getattr
(
self
,
name
):
def
getattr
(
self
,
name
):
return
self
.
current
.
attributes
.
get
(
name
,
[])
return
self
.
state
.
attributes
.
get
(
name
,
[])
def
setattr
(
self
,
name
,
values
):
def
setattr
(
self
,
name
,
values
):
oper
=
ModifyOperation
({
name
:
[(
MODIFY_REPLACE
,
[
values
])]})
oper
=
ModifyOperation
(
self
,
{
name
:
[(
MODIFY_REPLACE
,
[
values
])]})
if
self
.
session
is
not
None
:
oper
.
apply_object
(
obj
.
state
)
self
.
session
.
record
(
self
.
obj
,
oper
)
if
self
.
state
.
session
:
oper
.
apply
(
self
.
current
)
oper
.
apply_session
(
self
.
state
.
session
.
state
)
self
.
state
.
session
.
changes
.
append
(
oper
)
def
attr_append
(
self
,
name
,
value
):
def
attr_append
(
self
,
name
,
value
):
oper
=
ModifyOperation
({
name
:
[(
MODIFY_ADD
,
[
value
])]})
oper
=
ModifyOperation
(
self
,
{
name
:
[(
MODIFY_ADD
,
[
value
])]})
if
self
.
session
is
not
None
:
oper
.
apply_object
(
obj
.
state
)
self
.
session
.
record
(
self
.
obj
,
oper
)
if
self
.
state
.
session
:
oper
.
apply
(
self
.
current
)
oper
.
apply_session
(
self
.
state
.
session
.
state
)
self
.
state
.
session
.
changes
.
append
(
oper
)
def
attr_remove
(
self
,
name
,
value
):
def
attr_remove
(
self
,
name
,
value
):
# TODO: how does LDAP handle MODIFY_DELETE ops with non-existant values?
oper
=
ModifyOperation
(
self
,
{
name
:
[(
MODIFY_DELETE
,
[
value
])]})
oper
=
ModifyOperation
({
name
:
[(
MODIFY_DELETE
,
[
value
])]})
oper
.
apply_object
(
obj
.
state
)
if
self
.
session
is
not
None
:
if
self
.
state
.
session
:
self
.
session
.
record
(
self
.
obj
,
oper
)
oper
.
apply_session
(
self
.
state
.
session
.
state
)
oper
.
apply
(
self
.
current
)
self
.
state
.
session
.
changes
.
append
(
oper
)
# This is only a seperate class to keep SessionObject's namespace cleaner
class
SessionObject
:
ldap_mapper
=
None
ldap_object_classes
=
None
ldap_base
=
None
ldap_filter
=
None
def
__init__
(
self
,
__ldap_response
=
None
):
self
.
ldap_state
=
SessionObjectState
(
self
,
__ldap_response
)
@property
def
dn
(
self
):
raise
NotImplemented
()
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