Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
CIRCLE
/
cloud
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
94
Merge Requests
10
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
6f558426
authored
8 years ago
by
Czémán Arnold
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add LDAP and AD authentication
Issue:
#477
,
#478
parent
c177b3e8
Pipeline
#364
passed with stage
in 0 seconds
Changes
5
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
144 additions
and
10 deletions
+144
-10
circle/circle/settings/base.py
+81
-2
circle/dashboard/models.py
+55
-6
circle/dashboard/views/group.py
+2
-2
circle/dashboard/views/util.py
+4
-0
requirements/base.txt
+2
-0
No files found.
circle/circle/settings/base.py
View file @
6f558426
...
@@ -413,6 +413,11 @@ LOGGING = {
...
@@ -413,6 +413,11 @@ LOGGING = {
'level'
:
'INFO'
,
'level'
:
'INFO'
,
'propagate'
:
True
,
'propagate'
:
True
,
},
},
'django_auth_ldap'
:
{
'handlers'
:
[
'syslog'
],
'level'
:
'DEBUG'
,
'propagate'
:
True
,
},
}
}
}
}
########## END LOGGING CONFIGURATION
########## END LOGGING CONFIGURATION
...
@@ -446,6 +451,12 @@ CACHES = {
...
@@ -446,6 +451,12 @@ CACHES = {
}
}
AUTHENTICATION_BACKENDS
=
(
'django.contrib.auth.backends.ModelBackend'
,
)
######### SAML2 AUTHENTICATION
if
get_env_variable
(
'DJANGO_SAML'
,
'FALSE'
)
==
'TRUE'
:
if
get_env_variable
(
'DJANGO_SAML'
,
'FALSE'
)
==
'TRUE'
:
try
:
try
:
from
shutil
import
which
# python >3.4
from
shutil
import
which
# python >3.4
...
@@ -456,8 +467,7 @@ if get_env_variable('DJANGO_SAML', 'FALSE') == 'TRUE':
...
@@ -456,8 +467,7 @@ if get_env_variable('DJANGO_SAML', 'FALSE') == 'TRUE':
INSTALLED_APPS
+=
(
INSTALLED_APPS
+=
(
'djangosaml2'
,
'djangosaml2'
,
)
)
AUTHENTICATION_BACKENDS
=
(
AUTHENTICATION_BACKENDS
+=
(
'django.contrib.auth.backends.ModelBackend'
,
'common.backends.Saml2Backend'
,
'common.backends.Saml2Backend'
,
)
)
...
@@ -575,3 +585,72 @@ REQUEST_HOOK_URL = get_env_variable("REQUEST_HOOK_URL", "")
...
@@ -575,3 +585,72 @@ REQUEST_HOOK_URL = get_env_variable("REQUEST_HOOK_URL", "")
SSHKEY_EMAIL_ADD_KEY
=
False
SSHKEY_EMAIL_ADD_KEY
=
False
TWO_FACTOR_ISSUER
=
get_env_variable
(
"TWO_FACTOR_ISSUER"
,
"CIRCLE"
)
TWO_FACTOR_ISSUER
=
get_env_variable
(
"TWO_FACTOR_ISSUER"
,
"CIRCLE"
)
######### LDAP AUTHENTICATION
if
get_env_variable
(
'LDAP_AUTH'
,
'FALSE'
)
==
'TRUE'
:
import
ldap
from
django_auth_ldap.config
import
(
LDAPSearch
,
GroupOfNamesType
,
PosixGroupType
,
ActiveDirectoryGroupType
)
LDAP_SCOPE_MAP
=
{
"SUBTREE"
:
ldap
.
SCOPE_SUBTREE
,
"BASE"
:
ldap
.
SCOPE_BASE
,
"ONELEVEL"
:
ldap
.
SCOPE_SUBTREE
}
LDAP_GROUP_MAP
=
{
"POSIX"
:
PosixGroupType
(),
"AD"
:
ActiveDirectoryGroupType
(),
"GROUP_OF_NAMES"
:
GroupOfNamesType
(),
}
# Baseline configuration.
AUTH_LDAP_SERVER_URI
=
get_env_variable
(
"LDAP_SERVER_URI"
,
""
)
AUTH_LDAP_BIND_DN
=
get_env_variable
(
"LDAP_BIND_DN"
,
""
)
AUTH_LDAP_BIND_PASSWORD
=
get_env_variable
(
"LDAP_BIND_PASSWORD"
,
""
)
LDAP_USER_BASE_DN
=
get_env_variable
(
"LDAP_USER_BASE_DN"
)
LDAP_USER_SCOPE
=
LDAP_SCOPE_MAP
.
get
(
get_env_variable
(
"LDAP_USER_SCOPE"
,
""
))
LDAP_USER_FILTER
=
get_env_variable
(
"LDAP_USER_FILTER"
)
AUTH_LDAP_USER_SEARCH
=
LDAPSearch
(
LDAP_USER_BASE_DN
,
LDAP_USER_SCOPE
,
LDAP_USER_FILTER
)
# Set up the basic group parameters.
LDAP_GROUP_BASE_DN
=
get_env_variable
(
"LDAP_GROUP_BASE_DN"
)
LDAP_GROUP_SCOPE
=
LDAP_SCOPE_MAP
.
get
(
get_env_variable
(
"LDAP_GROUP_SCOPE"
,
""
))
LDAP_GROUP_FILTER
=
get_env_variable
(
"LDAP_GROUP_FILTER"
)
AUTH_LDAP_GROUP_SEARCH
=
LDAPSearch
(
LDAP_GROUP_BASE_DN
,
LDAP_GROUP_SCOPE
,
LDAP_GROUP_FILTER
)
LDAP_GROUP_TYPE
=
get_env_variable
(
"LDAP_GROUP_TYPE"
,
""
)
AUTH_LDAP_GROUP_TYPE
=
LDAP_GROUP_MAP
.
get
(
LDAP_GROUP_TYPE
,
"POSIX"
)
# Populate the Django user from the LDAP directory.
AUTH_LDAP_USER_ATTR_MAP
=
loads
(
get_env_variable
(
"LDAP_USER_ATTR_MAP"
,
'{"first_name": "givenName", "last_name": "sn", "email": "mail"}'
))
AUTH_LDAP_FIND_GROUP_PERMS
=
False
# Cache group memberships for an hour to minimize LDAP traffic
AUTH_LDAP_GROUP_CACHE_TIMEOUT
=
int
(
get_env_variable
(
"LDAP_GROUP_CACHE_TIMEOUT"
,
0
))
if
AUTH_LDAP_GROUP_CACHE_TIMEOUT
!=
0
:
AUTH_LDAP_CACHE_GROUPS
=
False
# Add LDAP backend
AUTHENTICATION_BACKENDS
+=
(
'django_auth_ldap.backend.LDAPBackend'
,
)
# org_id attribute
if
get_env_variable
(
'LDAP_ORG_ID_ATTRIBUTE'
,
False
):
LDAP_ORG_ID_ATTRIBUTE
=
get_env_variable
(
'LDAP_ORG_ID_ATTRIBUTE'
)
This diff is collapsed.
Click to expand it.
circle/dashboard/models.py
View file @
6f558426
...
@@ -341,22 +341,23 @@ def create_profile_hook(sender, user, request, **kwargs):
...
@@ -341,22 +341,23 @@ def create_profile_hook(sender, user, request, **kwargs):
user_logged_in
.
connect
(
create_profile_hook
)
user_logged_in
.
connect
(
create_profile_hook
)
if
hasattr
(
settings
,
'SAML_ORG_ID_ATTRIBUTE'
):
if
hasattr
(
settings
,
'SAML_ORG_ID_ATTRIBUTE'
):
logger
.
debug
(
"Register save_org_id to djangosaml2 pre_user_save"
)
logger
.
debug
(
"Register sa
ml_sa
ve_org_id to djangosaml2 pre_user_save"
)
from
djangosaml2.signals
import
pre_user_save
from
djangosaml2.signals
import
pre_user_save
def
save_org_id
(
sender
,
**
kwargs
):
def
sa
ml_sa
ve_org_id
(
sender
,
**
kwargs
):
logger
.
debug
(
"save_org_id called by
%
s"
,
sender
.
username
)
logger
.
debug
(
"sa
ml_sa
ve_org_id called by
%
s"
,
sender
.
username
)
attributes
=
kwargs
.
pop
(
'attributes'
)
attributes
=
kwargs
.
pop
(
'attributes'
)
atr
=
settings
.
SAML_ORG_ID_ATTRIBUTE
atr
=
settings
.
SAML_ORG_ID_ATTRIBUTE
try
:
try
:
value
=
attributes
[
atr
][
0
]
.
upper
()
value
=
attributes
[
atr
][
0
]
.
upper
()
except
Exception
as
e
:
except
Exception
as
e
:
value
=
None
value
=
None
logger
.
info
(
"save_org_id couldn't find attribute.
%
s"
,
unicode
(
e
))
logger
.
info
(
"saml_save_org_id couldn't find attribute.
%
s"
,
unicode
(
e
))
if
sender
.
pk
is
None
:
if
sender
.
pk
is
None
:
sender
.
save
()
sender
.
save
()
logger
.
debug
(
"save_org_id saved user
%
s"
,
unicode
(
sender
))
logger
.
debug
(
"sa
ml_sa
ve_org_id saved user
%
s"
,
unicode
(
sender
))
profile
,
created
=
Profile
.
objects
.
get_or_create
(
user
=
sender
)
profile
,
created
=
Profile
.
objects
.
get_or_create
(
user
=
sender
)
if
created
or
profile
.
org_id
!=
value
:
if
created
or
profile
.
org_id
!=
value
:
...
@@ -397,7 +398,55 @@ if hasattr(settings, 'SAML_ORG_ID_ATTRIBUTE'):
...
@@ -397,7 +398,55 @@ if hasattr(settings, 'SAML_ORG_ID_ATTRIBUTE'):
return
False
# User did not change
return
False
# User did not change
pre_user_save
.
connect
(
save_org_id
)
pre_user_save
.
connect
(
saml_save_org_id
)
if
hasattr
(
settings
,
'LDAP_ORG_ID_ATTRIBUTE'
):
logger
.
debug
(
"Register ldap_save_org_id to django-ldap-auth populate user"
)
from
django_auth_ldap.backend
import
populate_user
def
ldap_save_org_id
(
sender
,
user
,
ldap_user
,
**
kwargs
):
logger
.
debug
(
"ldap_save_org_id called by
%
s"
,
user
.
username
)
attributes
=
ldap_user
.
attrs
attr
=
settings
.
LDAP_ORG_ID_ATTRIBUTE
try
:
value
=
attributes
[
attr
][
0
]
.
upper
()
except
Exception
as
e
:
value
=
None
logger
.
info
(
"ldap_save_org_id couldn't find attribute.
%
s"
,
unicode
(
e
))
if
user
.
pk
is
None
:
user
.
save
()
logger
.
debug
(
"ldap_save_org_id saved user
%
s"
,
unicode
(
user
))
profile
,
created
=
Profile
.
objects
.
get_or_create
(
user
=
user
)
if
created
or
profile
.
org_id
!=
value
:
logger
.
info
(
"org_id of
%
s added to user
%
s's profile"
,
value
,
user
.
username
)
profile
.
org_id
=
value
profile
.
save
()
else
:
logger
.
debug
(
"org_id of
%
s already added to user
%
s's profile"
,
value
,
user
.
username
)
logger
.
error
(
ldap_user
.
group_dns
)
for
group
in
ldap_user
.
group_names
:
try
:
g
=
GroupProfile
.
search
(
group
)
except
Group
.
DoesNotExist
:
logger
.
debug
(
'cant find membergroup
%
s'
,
group
)
else
:
logger
.
debug
(
'could find membergroup
%
s (
%
s)'
,
group
,
unicode
(
g
))
g
.
user_set
.
add
(
user
)
for
i
in
FutureMember
.
objects
.
filter
(
org_id__iexact
=
value
):
i
.
group
.
user_set
.
add
(
user
)
i
.
delete
()
return
False
# User did not change
populate_user
.
connect
(
ldap_save_org_id
)
def
update_store_profile
(
sender
,
**
kwargs
):
def
update_store_profile
(
sender
,
**
kwargs
):
...
...
This diff is collapsed.
Click to expand it.
circle/dashboard/views/group.py
View file @
6f558426
...
@@ -42,7 +42,7 @@ from ..models import FutureMember, GroupProfile
...
@@ -42,7 +42,7 @@ from ..models import FutureMember, GroupProfile
from
vm.models
import
Instance
,
InstanceTemplate
from
vm.models
import
Instance
,
InstanceTemplate
from
..tables
import
GroupListTable
from
..tables
import
GroupListTable
from
.util
import
(
CheckedDetailView
,
AclUpdateView
,
search_user
,
from
.util
import
(
CheckedDetailView
,
AclUpdateView
,
search_user
,
saml_available
,
DeleteViewBase
)
saml_available
,
DeleteViewBase
,
external_auth_available
)
logger
=
logging
.
getLogger
(
__name__
)
logger
=
logging
.
getLogger
(
__name__
)
...
@@ -145,7 +145,7 @@ class GroupDetailView(CheckedDetailView):
...
@@ -145,7 +145,7 @@ class GroupDetailView(CheckedDetailView):
entity
=
search_user
(
name
)
entity
=
search_user
(
name
)
self
.
object
.
user_set
.
add
(
entity
)
self
.
object
.
user_set
.
add
(
entity
)
except
User
.
DoesNotExist
:
except
User
.
DoesNotExist
:
if
saml_available
:
if
external_auth_available
()
:
FutureMember
.
objects
.
get_or_create
(
org_id
=
name
.
upper
(),
FutureMember
.
objects
.
get_or_create
(
org_id
=
name
.
upper
(),
group
=
self
.
object
)
group
=
self
.
object
)
else
:
else
:
...
...
This diff is collapsed.
Click to expand it.
circle/dashboard/views/util.py
View file @
6f558426
...
@@ -60,6 +60,10 @@ logger = logging.getLogger(__name__)
...
@@ -60,6 +60,10 @@ logger = logging.getLogger(__name__)
saml_available
=
hasattr
(
settings
,
"SAML_CONFIG"
)
saml_available
=
hasattr
(
settings
,
"SAML_CONFIG"
)
def
external_auth_available
():
return
saml_available
or
hasattr
(
settings
,
"AUTH_LDAP_SERVER_URI"
)
class
RedirectToLoginMixin
(
AccessMixin
):
class
RedirectToLoginMixin
(
AccessMixin
):
redirect_exception_classes
=
(
PermissionDenied
,
)
redirect_exception_classes
=
(
PermissionDenied
,
)
...
...
This diff is collapsed.
Click to expand it.
requirements/base.txt
View file @
6f558426
...
@@ -42,3 +42,5 @@ pika==0.9.14
...
@@ -42,3 +42,5 @@ pika==0.9.14
django-pipeline==1.4.7
django-pipeline==1.4.7
Fabric==1.10.1
Fabric==1.10.1
lxml==3.4.4
lxml==3.4.4
django-auth-ldap==1.2.8
python-ldap==2.4.30
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment