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
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Operate
Terraform modules
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
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
Luca (strifel)
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
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
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
class
S
tatus
(
Enum
)
:
NEW
ADDED
DELETED
class
S
essionState
:
def
__init__
(
self
,
objects
=
None
,
deleted_objects
=
None
):
self
.
objects
=
objects
or
{}
self
.
deleted_objects
=
deleted_objects
or
{}
class
State
:
def
__init__
(
self
,
status
=
Status
.
NEW
,
attributes
=
None
):
self
.
status
=
status
def
copy
(
self
):
return
SessionState
(
objects
=
deepcopy
(
self
.
objects
),
deleted_objects
=
deepcopy
(
self
.
deleted_objects
))
class
ObjectState
:
def
__init__
(
self
,
session
=
None
,
attributes
=
None
,
dn
=
None
):
self
.
session
=
session
self
.
attributes
=
attributes
or
{}
self
.
dn
=
dn
def
copy
(
self
):
return
State
(
self
.
status
,
deepcopy
(
self
.
attributes
))
return
ObjectState
(
attributes
=
deepcopy
(
self
.
attributes
)
,
dn
=
self
.
dn
,
session
=
self
.
session
)
class
Operation
:
def
__init__
(
self
,
obj
):
class
Add
Operation
:
def
__init__
(
self
,
obj
,
dn
,
object_classes
):
self
.
obj
=
obj
self
.
dn
=
dn
self
.
object_classes
=
object_classes
self
.
attributes
=
deepcopy
(
obj
.
state
.
attributes
)
def
apply
(
self
,
state
):
raise
NotImplemented
()
def
execute
(
self
,
conn
):
raise
NotImplemented
()
def
extend
(
self
,
oper
):
return
False
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_object
(
self
,
obj_state
):
obj_state
.
dn
=
self
.
dn
obj_state
.
attributes
=
deepcopy
(
self
.
attributes
)
def
apply
(
self
,
state
):
state
.
status
=
Status
.
ADDED
s
tate
.
attributes
=
self
.
attributes
def
apply
_session
(
self
,
session_
state
):
assert
self
.
dn
not
in
session_state
.
objects
s
ession_state
.
objects
[
self
.
dn
]
=
self
.
obj
def
execute
(
self
,
conn
):
success
=
conn
.
add
(
self
.
obj
.
dn
,
self
.
ldap_
object_classes
,
self
.
attributes
)
def
apply_ldap
(
self
,
conn
):
success
=
conn
.
add
(
self
.
dn
,
self
.
object_classes
,
self
.
attributes
)
if
not
success
:
raise
LDAPCommitError
()
class
DeleteOperation
(
Operation
):
def
apply
(
self
,
state
):
state
.
status
=
Status
.
DELETED
class
DeleteOperation
:
def
__init__
(
self
,
obj
):
self
.
dn
=
obj
.
state
.
dn
self
.
obj
=
obj
def
apply_object
(
self
,
obj_state
):
obj_state
.
dn
=
None
def
apply_session
(
self
,
session_state
):
assert
self
.
dn
in
session_state
.
objects
del
session_state
.
objects
[
self
.
dn
]
session_state
.
deleted_objects
[
self
.
dn
]
=
self
.
obj
def
execute
(
self
,
conn
):
success
=
conn
.
delete
(
self
.
obj
.
dn
)
def
apply_ldap
(
self
,
conn
):
success
=
conn
.
delete
(
self
.
dn
)
if
not
success
:
raise
LDAPCommitError
()
class
ModifyOperation
(
Operation
)
:
class
ModifyOperation
:
def
__init__
(
self
,
obj
,
changes
):
s
uper
().
__init__
(
obj
)
s
elf
.
obj
=
obj
self
.
changes
=
deepcopy
(
changes
)
def
apply
(
self
,
state
):
def
apply
_object
(
self
,
obj_
state
):
for
attr
,
changes
in
self
.
changes
.
items
():
for
action
,
values
in
changes
:
if
action
==
MODIFY_REPLACE
:
state
.
attributes
[
attr
]
=
values
obj_
state
.
attributes
[
attr
]
=
values
elif
action
==
MODIFY_ADD
:
state
.
attributes
[
attr
]
+=
values
obj_
state
.
attributes
[
attr
]
+=
values
elif
action
==
MODIFY_DELETE
:
for
value
in
values
:
state
.
attributes
[
attr
].
remove
(
value
)
obj_state
.
attributes
[
attr
].
remove
(
value
)
def
apply_session
(
self
,
session_state
):
pass
def
execute
(
self
,
conn
):
success
=
conn
.
modify
(
self
.
obj
.
dn
,
self
.
changes
)
def
apply_ldap
(
self
,
conn
):
success
=
conn
.
modify
(
self
.
obj
.
state
.
dn
,
self
.
changes
)
if
not
success
:
raise
LDAPCommitError
()
class
Session
:
ldap_mapper
=
None
def
__init__
(
self
,
get_connection
):
self
.
get_connection
=
get_connection
self
.
committed_state
=
SessionState
()
self
.
state
=
SessionState
()
self
.
changes
=
[]
def
add
(
self
,
obj
,
dn
,
object_classes
):
if
self
.
state
.
objects
.
get
(
dn
)
==
obj
:
return
assert
obj
.
state
.
session
is
None
oper
=
AddOperation
(
obj
,
dn
,
object_classes
)
oper
.
apply_object
(
obj
.
state
)
oper
.
apply_session
(
self
.
state
)
self
.
changes
.
append
(
oper
)
def
__init__
(
self
):
self
.
__objects
=
{}
self
.
__deleted_objects
=
{}
self
.
__operations
=
[]
def
delete
(
self
,
obj
):
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
)
# Never called directly!
def
record
(
self
,
oper
):
if
isinstance
(
oper
,
AddOperation
):
if
oper
.
obj
.
ldap_state
.
session
==
self
:
return
if
oper
.
obj
.
ldap_state
.
session
is
not
None
:
raise
Exception
()
if
oper
.
obj
.
dn
in
self
.
__objects
:
raise
Exception
()
self
.
__objects
[
oper
.
obj
.
dn
]
=
oper
.
obj
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
):
obj
.
ldap_state
.
delete
()
assert
oper
.
obj
.
state
.
session
==
self
self
.
changes
.
append
(
oper
)
def
commit
(
self
):
conn
=
self
.
mapper
.
connect
()
while
self
.
__operation
s
:
obj
,
oper
=
self
.
__operation
s
.
pop
(
0
)
conn
=
self
.
get_
connect
ion
()
while
self
.
change
s
:
oper
=
self
.
change
s
.
pop
(
0
)
try
:
oper
.
execute
(
obj
.
dn
,
conn
)
oper
.
apply_ldap
(
conn
)
except
e
:
self
.
__operation
s
.
insert
(
0
,
(
obj
,
oper
)
)
self
.
change
s
.
insert
(
0
,
oper
)
raise
e
oper
.
apply_object
(
oper
.
obj
.
committed_state
)
oper
.
apply_session
(
self
.
committed_state
)
self
.
committed_state
=
self
.
state
.
copy
()
def
rollback
(
self
):
while
self
.
__operations
:
obj
,
oper
=
self
.
__operations
.
pop
(
0
)
obj
.
ldap_state
.
current
=
obj
.
ldap_state
.
committed
.
copy
()
def
query_get
(
self
,
cls
,
dn
):
if
dn
in
self
.
__objects
:
return
self
.
__objects
[
dn
]
if
dn
in
self
.
__deleted_objects
:
for
obj
in
self
.
state
.
objects
.
values
():
obj
.
state
=
obj
.
committed_state
.
copy
()
for
obj
in
self
.
state
.
deleted_objects
.
values
():
obj
.
state
=
obj
.
committed_state
.
copy
()
self
.
state
=
self
.
committed_state
.
copy
()
self
.
changes
.
clear
()
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
conn
=
self
.
mapper
.
connect
()
conn
.
search
(
dn
,
cls
.
ldap
_filter
,
attributes
=
[
ALL_ATTRIBUTES
,
ALL_OPERATIONAL_ATTRIBUTES
])
conn
=
self
.
get_
connect
ion
()
conn
.
search
(
dn
,
search
_filter
,
attributes
=
[
ALL_ATTRIBUTES
,
ALL_OPERATIONAL_ATTRIBUTES
])
if
not
conn
.
response
:
return
None
self
.
__objects
[
dn
]
=
cls
(
__ldap_response
=
conn
.
response
[
0
])
return
self
.
__objects
[
dn
]
def
query_search
(
self
,
cls
,
filters
=
None
):
filters
=
[
cls
.
ldap_filter
]
+
(
filters
or
[])
if
len
(
filters
)
==
1
:
expr
=
filters
[
0
]
else
:
expr
=
'
(&%s)
'
%
(
''
.
join
(
filters
))
conn
=
self
.
mapper
.
connect
()
conn
.
search
(
cls
.
ldap_base
,
cls
.
ldap_filter
,
attributes
=
[
ALL_ATTRIBUTES
,
ALL_OPERATIONAL_ATTRIBUTES
])
assert
len
(
conn
.
response
)
==
1
assert
conn
.
response
[
0
][
'
dn
'
]
==
dn
self
.
state
.
objects
[
dn
]
=
Object
(
self
,
conn
.
response
[
0
])
self
.
committed_state
.
objects
[
dn
]
=
self
.
state
.
objects
[
dn
]
return
self
.
state
.
objects
[
dn
]
def
search
(
self
,
search_base
,
search_filter
):
conn
=
self
.
get_connection
()
conn
.
search
(
search_base
,
search_filter
,
attributes
=
[
ALL_ATTRIBUTES
,
ALL_OPERATIONAL_ATTRIBUTES
])
res
=
[]
for
response
in
conn
.
response
:
dn
=
response
[
'
dn
'
]
if
dn
in
self
.
__
objects
:
res
.
append
(
self
.
__
objects
[
dn
])
elif
dn
in
self
.
__
deleted_objects
:
if
dn
in
self
.
state
.
objects
:
res
.
append
(
self
.
state
.
objects
[
dn
])
elif
dn
in
self
.
state
.
deleted_objects
:
continue
else
:
self
.
__objects
[
dn
]
=
cls
(
__ldap_response
=
response
)
res
.
append
(
self
.
__objects
[
dn
])
self
.
state
.
objects
[
dn
]
=
Object
(
self
,
response
)
self
.
committed_state
.
objects
[
dn
]
=
self
.
state
.
objects
[
dn
]
res
.
append
(
self
.
state
.
objects
[
dn
])
return
res
# This is only a seperate class to keep SessionObject's namespace cleaner
class
SessionObjectState
:
def
__init__
(
self
,
obj
,
response
=
None
):
self
.
obj
=
obj
self
.
session
=
None
if
response
is
not
None
:
self
.
commited
=
State
()
class
Object
:
def
__init__
(
self
,
session
=
None
,
response
=
None
):
if
response
is
None
:
self
.
committed_state
=
ObjectState
()
else
:
self
.
commited
=
State
(
Status
.
ADDED
,
response
[
'
attributes
'
])
self
.
current
=
self
.
commited
.
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
)
assert
session
is
not
None
self
.
committed_state
=
ObjectState
(
session
,
response
[
'
attributes
'
],
response
[
'
dn
'
])
self
.
state
=
self
.
committed_state
.
copy
()
def
getattr
(
self
,
name
):
return
self
.
current
.
attributes
.
get
(
name
,
[])
return
self
.
state
.
attributes
.
get
(
name
,
[])
def
setattr
(
self
,
name
,
values
):
oper
=
ModifyOperation
({
name
:
[(
MODIFY_REPLACE
,
[
values
])]})
if
self
.
session
is
not
None
:
self
.
session
.
record
(
self
.
obj
,
oper
)
oper
.
apply
(
self
.
current
)
oper
=
ModifyOperation
(
self
,
{
name
:
[(
MODIFY_REPLACE
,
[
values
])]})
oper
.
apply_object
(
obj
.
state
)
if
self
.
state
.
session
:
oper
.
apply_session
(
self
.
state
.
session
.
state
)
self
.
state
.
session
.
changes
.
append
(
oper
)
def
attr_append
(
self
,
name
,
value
):
oper
=
ModifyOperation
({
name
:
[(
MODIFY_ADD
,
[
value
])]})
if
self
.
session
is
not
None
:
self
.
session
.
record
(
self
.
obj
,
oper
)
oper
.
apply
(
self
.
current
)
oper
=
ModifyOperation
(
self
,
{
name
:
[(
MODIFY_ADD
,
[
value
])]})
oper
.
apply_object
(
obj
.
state
)
if
self
.
state
.
session
:
oper
.
apply_session
(
self
.
state
.
session
.
state
)
self
.
state
.
session
.
changes
.
append
(
oper
)
def
attr_remove
(
self
,
name
,
value
):
# TODO: how does LDAP handle MODIFY_DELETE ops with non-existant values?
oper
=
ModifyOperation
({
name
:
[(
MODIFY_DELETE
,
[
value
])]})
if
self
.
session
is
not
None
:
self
.
session
.
record
(
self
.
obj
,
oper
)
oper
.
apply
(
self
.
current
)
# 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
()
oper
=
ModifyOperation
(
self
,
{
name
:
[(
MODIFY_DELETE
,
[
value
])]})
oper
.
apply_object
(
obj
.
state
)
if
self
.
state
.
session
:
oper
.
apply_session
(
self
.
state
.
session
.
state
)
self
.
state
.
session
.
changes
.
append
(
oper
)
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