Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
D
django-openid-auth
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
django-openid-auth
Commits
63b625b3
Commit
63b625b3
authored
Sep 08, 2015
by
Ricardo Kirkner
Browse files
Options
Browse Files
Download
Plain Diff
merged in latest trunk
parents
89a81066
201c1f3a
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
515 additions
and
394 deletions
+515
-394
.bzrignore
+5
-6
Makefile
+3
-4
django_openid_auth/__init__.py
+0
-1
django_openid_auth/admin.py
+37
-19
django_openid_auth/auth.py
+27
-21
django_openid_auth/exceptions.py
+12
-3
django_openid_auth/forms.py
+9
-7
django_openid_auth/management/commands/openid_cleanup.py
+2
-0
django_openid_auth/migrations/0001_initial.py
+54
-116
django_openid_auth/models.py
+4
-5
django_openid_auth/signals.py
+2
-0
django_openid_auth/south_migrations/0001_initial.py
+117
-0
django_openid_auth/south_migrations/0002_add_perm_account_verified.py
+0
-0
django_openid_auth/south_migrations/__init__.py
+0
-0
django_openid_auth/store.py
+5
-1
django_openid_auth/teams.py
+19
-17
django_openid_auth/tests/__init__.py
+5
-15
django_openid_auth/tests/helpers.py
+2
-0
django_openid_auth/tests/test_admin.py
+18
-36
django_openid_auth/tests/test_auth.py
+0
-0
django_openid_auth/tests/test_models.py
+1
-5
django_openid_auth/tests/test_settings.py
+34
-15
django_openid_auth/tests/test_store.py
+2
-5
django_openid_auth/tests/test_views.py
+0
-0
django_openid_auth/tests/urls.py
+6
-2
django_openid_auth/urls.py
+5
-2
django_openid_auth/views.py
+32
-22
example_consumer/settings.py
+61
-71
example_consumer/urls.py
+8
-7
example_consumer/wsgi.py
+14
-0
manage.py
+1
-1
setup.py
+1
-1
tox.ini
+29
-12
No files found.
.bzrignore
View file @
63b625b3
./django
./MANIFEST
./build
./dist
./sqlite.db
./.tox/
MANIFEST
build
dist
db.sqlite3
.tox
Makefile
View file @
63b625b3
check
:
PYTHONPATH
=
$(
shell
pwd
)
python example_consumer/manage.py
test
\
--verbosity
=
2 django_openid_auth
PYTHONPATH
=
$(
shell
pwd
)
python manage.py
test
--verbosity
=
2 django_openid_auth
run-example-consumer
:
PYTHONPATH
=
$(
shell
pwd
)
python
example_consumer/manage.py syncdb
PYTHONPATH
=
$(
shell
pwd
)
python
example_consumer/
manage.py runserver
PYTHONPATH
=
$(
shell
pwd
)
python
manage.py syncdb
--migrate
PYTHONPATH
=
$(
shell
pwd
)
python manage.py runserver
.PHONY
:
check run-example-consumer
django_openid_auth/__init__.py
View file @
63b625b3
...
...
@@ -26,4 +26,3 @@
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
django_openid_auth/admin.py
View file @
63b625b3
...
...
@@ -27,8 +27,15 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from
__future__
import
unicode_literals
from
urllib
import
urlencode
from
urlparse
import
parse_qsl
,
urlparse
from
django.conf
import
settings
from
django.contrib
import
admin
from
django.http
import
HttpResponseRedirect
from
django_openid_auth
import
views
from
django_openid_auth.models
import
Nonce
,
Association
,
UserOpenID
from
django_openid_auth.store
import
DjangoOpenIDStore
...
...
@@ -69,22 +76,33 @@ class UserOpenIDAdmin(admin.ModelAdmin):
admin
.
site
.
register
(
UserOpenID
,
UserOpenIDAdmin
)
# Support for allowing openid authentication for /admin (django.contrib.admin)
if
getattr
(
settings
,
'OPENID_USE_AS_ADMIN_LOGIN'
,
False
):
from
django.http
import
HttpResponseRedirect
from
django_openid_auth
import
views
def
_openid_login
(
self
,
request
,
error_message
=
''
,
extra_context
=
None
):
if
request
.
user
.
is_authenticated
():
if
not
request
.
user
.
is_staff
:
return
views
.
default_render_failure
(
request
,
"User
%
s does not have admin access."
%
request
.
user
.
username
)
assert
error_message
,
"Unknown Error:
%
s"
%
error_message
else
:
# Redirect to openid login path,
return
HttpResponseRedirect
(
settings
.
LOGIN_URL
+
"?next="
+
request
.
get_full_path
())
# Overide the standard admin login form.
admin
.
sites
.
AdminSite
.
login
=
_openid_login
# store a reference to the original admin login
original_admin_login
=
admin
.
sites
.
AdminSite
.
login
def
_openid_login
(
instance
,
request
,
error_message
=
''
,
extra_context
=
None
):
# Support for allowing openid authentication for /admin
# (django.contrib.admin)
if
not
getattr
(
settings
,
'OPENID_USE_AS_ADMIN_LOGIN'
,
False
):
return
original_admin_login
(
instance
,
request
,
extra_context
=
extra_context
)
if
not
request
.
user
.
is_authenticated
():
# Redirect to openid login path,
_
,
_
,
path
,
_
,
query
,
_
=
urlparse
(
request
.
get_full_path
())
qs
=
dict
(
parse_qsl
(
query
))
qs
.
setdefault
(
'next'
,
path
)
return
HttpResponseRedirect
(
settings
.
LOGIN_URL
+
"?"
+
urlencode
(
qs
))
if
not
request
.
user
.
is_staff
:
return
views
.
default_render_failure
(
request
,
"User
%
s does not have admin/staff access."
%
request
.
user
.
username
)
# No error message was supplied
assert
error_message
,
"Unknown Error:
%
s"
%
error_message
# Overide the standard admin login form.
admin
.
sites
.
AdminSite
.
login
=
_openid_login
django_openid_auth/auth.py
View file @
63b625b3
...
...
@@ -28,6 +28,8 @@
"""Glue between OpenID and django.contrib.auth."""
from
__future__
import
unicode_literals
__metaclass__
=
type
import
re
...
...
@@ -93,8 +95,9 @@ class OpenIDBackend:
if
getattr
(
settings
,
'OPENID_PHYSICAL_MULTIFACTOR_REQUIRED'
,
False
):
pape_response
=
pape
.
Response
.
fromSuccessResponse
(
openid_response
)
if
pape_response
is
None
or
\
pape
.
AUTH_MULTI_FACTOR_PHYSICAL
not
in
pape_response
.
auth_policies
:
key
=
pape
.
AUTH_MULTI_FACTOR_PHYSICAL
if
(
pape_response
is
None
or
key
not
in
pape_response
.
auth_policies
):
raise
MissingPhysicalMultiFactor
()
teams_response
=
teams
.
TeamsResponse
.
fromSuccessResponse
(
...
...
@@ -165,7 +168,7 @@ class OpenIDBackend:
if
len
(
split_names
)
==
2
:
first_name
,
last_name
=
split_names
else
:
first_name
=
u
''
first_name
=
''
last_name
=
fullname
verification_scheme_map
=
getattr
(
...
...
@@ -194,12 +197,13 @@ class OpenIDBackend:
if
nickname
is
None
or
nickname
==
''
:
raise
MissingUsernameViolation
()
# If we don't have a nickname, and we're not being strict, use a default
# If we don't have a nickname, and we're not being strict, use a
# default
nickname
=
nickname
or
'openiduser'
# See if we already have this nickname assigned to a username
try
:
user
=
User
.
objects
.
get
(
username__exact
=
nickname
)
User
.
objects
.
get
(
username__exact
=
nickname
)
except
User
.
DoesNotExist
:
# No conflict, we can use this nickname
return
nickname
...
...
@@ -231,7 +235,6 @@ class OpenIDBackend:
# No user associated with this identity_url
pass
if
getattr
(
settings
,
'OPENID_STRICT_USERNAMES'
,
False
):
if
User
.
objects
.
filter
(
username__exact
=
nickname
)
.
count
()
>
0
:
raise
DuplicateUsernameViolation
(
...
...
@@ -248,7 +251,7 @@ class OpenIDBackend:
if
i
>
1
:
username
+=
str
(
i
)
try
:
user
=
User
.
objects
.
get
(
username__exact
=
username
)
User
.
objects
.
get
(
username__exact
=
username
)
except
User
.
DoesNotExist
:
break
i
+=
1
...
...
@@ -266,12 +269,12 @@ class OpenIDBackend:
"An attribute required for logging in was not "
"returned ({0})."
.
format
(
required_attr
))
nickname
=
self
.
_get_preferred_username
(
details
[
'nickname'
],
details
[
'email'
])
nickname
=
self
.
_get_preferred_username
(
details
[
'
nickname'
],
details
[
'
email'
])
email
=
details
[
'email'
]
or
''
username
=
self
.
_get_available_username
(
nickname
,
openid_response
.
identity_url
)
username
=
self
.
_get_available_username
(
nickname
,
openid_response
.
identity_url
)
user
=
User
.
objects
.
create_user
(
username
,
email
,
password
=
None
)
self
.
associate_openid
(
user
,
openid_response
)
...
...
@@ -328,13 +331,16 @@ class OpenIDBackend:
user
.
save
()
def
get_teams_mapping
(
self
):
teams_mapping_auto
=
getattr
(
settings
,
'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO'
,
False
)
teams_mapping_auto_blacklist
=
getattr
(
settings
,
'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO_BLACKLIST'
,
[])
teams_mapping_auto
=
getattr
(
settings
,
'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO'
,
False
)
teams_mapping_auto_blacklist
=
getattr
(
settings
,
'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO_BLACKLIST'
,
[])
teams_mapping
=
getattr
(
settings
,
'OPENID_LAUNCHPAD_TEAMS_MAPPING'
,
{})
if
teams_mapping_auto
:
#ignore teams_mapping. use all django-groups
#
ignore teams_mapping. use all django-groups
teams_mapping
=
dict
()
all_groups
=
Group
.
objects
.
exclude
(
name__in
=
teams_mapping_auto_blacklist
)
all_groups
=
Group
.
objects
.
exclude
(
name__in
=
teams_mapping_auto_blacklist
)
for
group
in
all_groups
:
teams_mapping
[
group
.
name
]
=
group
.
name
return
teams_mapping
...
...
@@ -344,12 +350,12 @@ class OpenIDBackend:
if
len
(
teams_mapping
)
==
0
:
return
current_groups
=
set
(
user
.
groups
.
filter
(
name__in
=
teams_mapping
.
values
()))
desired_groups
=
set
(
Group
.
objects
.
filter
(
name__in
=
[
teams_mapping
[
lp_team
]
for
lp_team
in
teams_response
.
is_member
if
lp_team
in
teams_mapping
]
))
mapping
=
[
teams_mapping
[
lp_team
]
for
lp_team
in
teams_response
.
is_member
if
lp_team
in
teams_mapping
]
current_groups
=
set
(
user
.
groups
.
filter
(
name__in
=
teams_mapping
.
values
()))
desired_groups
=
set
(
Group
.
objects
.
filter
(
name__in
=
mapping
))
for
group
in
current_groups
-
desired_groups
:
user
.
groups
.
remove
(
group
)
for
group
in
desired_groups
-
current_groups
:
...
...
django_openid_auth/exceptions.py
View file @
63b625b3
...
...
@@ -28,20 +28,27 @@
"""Exception classes thrown by OpenID Authentication and Validation."""
from
__future__
import
unicode_literals
class
DjangoOpenIDException
(
Exception
):
pass
class
RequiredAttributeNotReturned
(
DjangoOpenIDException
):
pass
class
IdentityAlreadyClaimed
(
DjangoOpenIDException
):
def
__init__
(
self
,
message
=
None
):
if
message
is
None
:
self
.
message
=
"Another user already exists for your selected OpenID"
self
.
message
=
(
"Another user already exists for your selected OpenID"
)
else
:
self
.
message
=
message
class
DuplicateUsernameViolation
(
DjangoOpenIDException
):
def
__init__
(
self
,
message
=
None
):
...
...
@@ -50,6 +57,7 @@ class DuplicateUsernameViolation(DjangoOpenIDException):
else
:
self
.
message
=
message
class
MissingUsernameViolation
(
DjangoOpenIDException
):
def
__init__
(
self
,
message
=
None
):
...
...
@@ -58,11 +66,12 @@ class MissingUsernameViolation(DjangoOpenIDException):
else
:
self
.
message
=
message
class
MissingPhysicalMultiFactor
(
DjangoOpenIDException
):
def
__init__
(
self
,
message
=
None
):
if
message
is
None
:
self
.
message
=
"Login requires physical multi-factor authentication."
self
.
message
=
(
"Login requires physical multi-factor authentication."
)
else
:
self
.
message
=
message
django_openid_auth/forms.py
View file @
63b625b3
...
...
@@ -27,6 +27,8 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from
__future__
import
unicode_literals
from
django
import
forms
from
django.contrib.auth.admin
import
UserAdmin
from
django.contrib.auth.forms
import
UserChangeForm
...
...
@@ -49,6 +51,7 @@ def teams_new_unicode(self):
return
"
%
s ->
%
s"
%
(
name
,
", "
.
join
(
group_teams
))
else
:
return
name
Group
.
unicode_before_teams
=
Group
.
__unicode__
Group
.
__unicode__
=
teams_new_unicode
...
...
@@ -64,9 +67,11 @@ class UserChangeFormWithTeamRestriction(UserChangeForm):
user_groups
=
self
.
instance
.
groups
.
all
()
for
group
in
data
:
if
group
.
name
in
known_teams
and
group
not
in
user_groups
:
raise
forms
.
ValidationError
(
"""The group
%
s is mapped to an
external team. You cannot assign it manually."""
%
group
.
name
)
raise
forms
.
ValidationError
(
"The group
%
s is mapped to an external team. "
"You cannot assign it manually."
%
group
.
name
)
return
data
UserAdmin
.
form
=
UserChangeFormWithTeamRestriction
...
...
@@ -78,10 +83,7 @@ class OpenIDLoginForm(forms.Form):
def
clean_openid_identifier
(
self
):
if
'openid_identifier'
in
self
.
cleaned_data
:
openid_identifier
=
self
.
cleaned_data
[
'openid_identifier'
]
if
xri
.
identifierScheme
(
openid_identifier
)
==
'XRI'
and
getattr
(
settings
,
'OPENID_DISALLOW_INAMES'
,
False
):
if
(
xri
.
identifierScheme
(
openid_identifier
)
==
'XRI'
and
getattr
(
settings
,
'OPENID_DISALLOW_INAMES'
,
False
)):
raise
forms
.
ValidationError
(
_
(
'i-names are not supported'
))
return
self
.
cleaned_data
[
'openid_identifier'
]
django_openid_auth/management/commands/openid_cleanup.py
View file @
63b625b3
...
...
@@ -26,6 +26,8 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from
__future__
import
unicode_literals
from
django.core.management.base
import
NoArgsCommand
from
django_openid_auth.store
import
DjangoOpenIDStore
...
...
django_openid_auth/migrations/0001_initial.py
View file @
63b625b3
# -*- coding: utf-8 -*-
import
datetime
from
south.db
import
db
from
south.v2
import
SchemaMigration
from
django.db
import
models
class
Migration
(
SchemaMigration
):
def
forwards
(
self
,
orm
):
# Adding model 'Nonce'
db
.
create_table
(
u'django_openid_auth_nonce'
,
(
(
u'id'
,
self
.
gf
(
'django.db.models.fields.AutoField'
)(
primary_key
=
True
)),
(
'server_url'
,
self
.
gf
(
'django.db.models.fields.CharField'
)(
max_length
=
2047
)),
(
'timestamp'
,
self
.
gf
(
'django.db.models.fields.IntegerField'
)()),
(
'salt'
,
self
.
gf
(
'django.db.models.fields.CharField'
)(
max_length
=
40
)),
))
db
.
send_create_signal
(
u'django_openid_auth'
,
[
'Nonce'
])
# Adding model 'Association'
db
.
create_table
(
u'django_openid_auth_association'
,
(
(
u'id'
,
self
.
gf
(
'django.db.models.fields.AutoField'
)(
primary_key
=
True
)),
(
'server_url'
,
self
.
gf
(
'django.db.models.fields.TextField'
)(
max_length
=
2047
)),
(
'handle'
,
self
.
gf
(
'django.db.models.fields.CharField'
)(
max_length
=
255
)),
(
'secret'
,
self
.
gf
(
'django.db.models.fields.TextField'
)(
max_length
=
255
)),
(
'issued'
,
self
.
gf
(
'django.db.models.fields.IntegerField'
)()),
(
'lifetime'
,
self
.
gf
(
'django.db.models.fields.IntegerField'
)()),
(
'assoc_type'
,
self
.
gf
(
'django.db.models.fields.TextField'
)(
max_length
=
64
)),
))
db
.
send_create_signal
(
u'django_openid_auth'
,
[
'Association'
])
# Adding model 'UserOpenID'
db
.
create_table
(
u'django_openid_auth_useropenid'
,
(
(
u'id'
,
self
.
gf
(
'django.db.models.fields.AutoField'
)(
primary_key
=
True
)),
(
'user'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
to
=
orm
[
'auth.User'
])),
(
'claimed_id'
,
self
.
gf
(
'django.db.models.fields.TextField'
)(
unique
=
True
,
max_length
=
2047
)),
(
'display_id'
,
self
.
gf
(
'django.db.models.fields.TextField'
)(
max_length
=
2047
)),
))
db
.
send_create_signal
(
u'django_openid_auth'
,
[
'UserOpenID'
])
def
backwards
(
self
,
orm
):
# Deleting model 'Nonce'
db
.
delete_table
(
u'django_openid_auth_nonce'
)
# Deleting model 'Association'
db
.
delete_table
(
u'django_openid_auth_association'
)
# Deleting model 'UserOpenID'
db
.
delete_table
(
u'django_openid_auth_useropenid'
)
models
=
{
u'auth.group'
:
{
'Meta'
:
{
'object_name'
:
'Group'
},
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'80'
}),
'permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
u"orm['auth.Permission']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
})
},
u'auth.permission'
:
{
'Meta'
:
{
'ordering'
:
"(u'content_type__app_label', u'content_type__model', u'codename')"
,
'unique_together'
:
"((u'content_type', u'codename'),)"
,
'object_name'
:
'Permission'
},
'codename'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'content_type'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['contenttypes.ContentType']"
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'50'
})
},
u'auth.user'
:
{
'Meta'
:
{
'object_name'
:
'User'
},
'date_joined'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'email'
:
(
'django.db.models.fields.EmailField'
,
[],
{
'max_length'
:
'75'
,
'blank'
:
'True'
}),
'first_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'groups'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
u"orm['auth.Group']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'is_active'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'is_staff'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'is_superuser'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'last_login'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'last_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'password'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'128'
}),
'user_permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
u"orm['auth.Permission']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
'username'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'30'
})
},
u'contenttypes.contenttype'
:
{
'Meta'
:
{
'ordering'
:
"('name',)"
,
'unique_together'
:
"(('app_label', 'model'),)"
,
'object_name'
:
'ContentType'
,
'db_table'
:
"'django_content_type'"
},
'app_label'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'model'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
})
},
u'django_openid_auth.association'
:
{
'Meta'
:
{
'object_name'
:
'Association'
},
'assoc_type'
:
(
'django.db.models.fields.TextField'
,
[],
{
'max_length'
:
'64'
}),
'handle'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'255'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'issued'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'lifetime'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'secret'
:
(
'django.db.models.fields.TextField'
,
[],
{
'max_length'
:
'255'
}),
'server_url'
:
(
'django.db.models.fields.TextField'
,
[],
{
'max_length'
:
'2047'
})
},
u'django_openid_auth.nonce'
:
{
'Meta'
:
{
'object_name'
:
'Nonce'
},
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'salt'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'40'
}),
'server_url'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'2047'
}),
'timestamp'
:
(
'django.db.models.fields.IntegerField'
,
[],
{})
},
u'django_openid_auth.useropenid'
:
{
'Meta'
:
{
'object_name'
:
'UserOpenID'
},
'claimed_id'
:
(
'django.db.models.fields.TextField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'2047'
}),
'display_id'
:
(
'django.db.models.fields.TextField'
,
[],
{
'max_length'
:
'2047'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['auth.User']"
})
}
}
complete_apps
=
[
'django_openid_auth'
]
\ No newline at end of file
from
__future__
import
unicode_literals
from
django.db
import
models
,
migrations
from
django.conf
import
settings
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
migrations
.
swappable_dependency
(
settings
.
AUTH_USER_MODEL
),
]
operations
=
[
migrations
.
CreateModel
(
name
=
'Association'
,
fields
=
[
(
'id'
,
models
.
AutoField
(
verbose_name
=
'ID'
,
serialize
=
False
,
auto_created
=
True
,
primary_key
=
True
)),
(
'server_url'
,
models
.
TextField
(
max_length
=
2047
)),
(
'handle'
,
models
.
CharField
(
max_length
=
255
)),
(
'secret'
,
models
.
TextField
(
max_length
=
255
)),
(
'issued'
,
models
.
IntegerField
()),
(
'lifetime'
,
models
.
IntegerField
()),
(
'assoc_type'
,
models
.
TextField
(
max_length
=
64
)),
],
options
=
{
},
bases
=
(
models
.
Model
,),
),
migrations
.
CreateModel
(
name
=
'Nonce'
,
fields
=
[
(
'id'
,
models
.
AutoField
(
verbose_name
=
'ID'
,
serialize
=
False
,
auto_created
=
True
,
primary_key
=
True
)),
(
'server_url'
,
models
.
CharField
(
max_length
=
2047
)),
(
'timestamp'
,
models
.
IntegerField
()),
(
'salt'
,
models
.
CharField
(
max_length
=
40
)),
],
options
=
{
},
bases
=
(
models
.
Model
,),
),
migrations
.
CreateModel
(
name
=
'UserOpenID'
,
fields
=
[
(
'id'
,
models
.
AutoField
(
verbose_name
=
'ID'
,
serialize
=
False
,
auto_created
=
True
,
primary_key
=
True
)),
(
'claimed_id'
,
models
.
TextField
(
unique
=
True
,
max_length
=
2047
)),
(
'display_id'
,
models
.
TextField
(
max_length
=
2047
)),
(
'user'
,
models
.
ForeignKey
(
to
=
settings
.
AUTH_USER_MODEL
)),
],
options
=
{
'permissions'
:
((
'account_verified'
,
'The OpenID has been verified'
),),
},
bases
=
(
models
.
Model
,),
),
]
django_openid_auth/models.py
View file @
63b625b3
...
...
@@ -27,11 +27,10 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from
django.contrib.auth.models
import
(
Permission
,
User
,
)
from
__future__
import
unicode_literals
from
django.db
import
models
from
django.contrib.auth.models
import
Permission
,
User
class
Nonce
(
models
.
Model
):
...
...
@@ -46,7 +45,7 @@ class Nonce(models.Model):
class
Association
(
models
.
Model
):
server_url
=
models
.
TextField
(
max_length
=
2047
)
handle
=
models
.
CharField
(
max_length
=
255
)
secret
=
models
.
TextField
(
max_length
=
255
)
# Stored base64 encoded
secret
=
models
.
TextField
(
max_length
=
255
)
# Stored base64 encoded
issued
=
models
.
IntegerField
()
lifetime
=
models
.
IntegerField
()
assoc_type
=
models
.
TextField
(
max_length
=
64
)
...
...
django_openid_auth/signals.py
View file @
63b625b3
...
...
@@ -27,6 +27,8 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from
__future__
import
unicode_literals
import
django.dispatch
...
...
django_openid_auth/south_migrations/0001_initial.py
0 → 100644
View file @
63b625b3
# -*- coding: utf-8 -*-
import
datetime
from
south.db
import
db
from
south.v2
import
SchemaMigration
from
django.db
import
models
class
Migration
(
SchemaMigration
):
def
forwards
(
self
,
orm
):
# Adding model 'Nonce'
db
.
create_table
(
u'django_openid_auth_nonce'
,
(
(
u'id'
,
self
.
gf
(
'django.db.models.fields.AutoField'
)(
primary_key
=
True
)),
(
'server_url'
,
self
.
gf
(
'django.db.models.fields.CharField'
)(
max_length
=
2047
)),
(
'timestamp'
,
self
.
gf
(
'django.db.models.fields.IntegerField'
)()),
(
'salt'
,
self
.
gf
(
'django.db.models.fields.CharField'
)(
max_length
=
40
)),
))
db
.
send_create_signal
(
u'django_openid_auth'
,
[
'Nonce'
])
# Adding model 'Association'
db
.
create_table
(
u'django_openid_auth_association'
,
(
(
u'id'
,
self
.
gf
(
'django.db.models.fields.AutoField'
)(
primary_key
=
True
)),
(
'server_url'
,
self
.
gf
(
'django.db.models.fields.TextField'
)(
max_length
=
2047
)),
(
'handle'
,
self
.
gf
(
'django.db.models.fields.CharField'
)(
max_length
=
255
)),
(
'secret'
,
self
.
gf
(
'django.db.models.fields.TextField'
)(
max_length
=
255
)),
(
'issued'
,
self
.
gf
(
'django.db.models.fields.IntegerField'
)()),
(
'lifetime'
,
self
.
gf
(
'django.db.models.fields.IntegerField'
)()),
(
'assoc_type'
,
self
.
gf
(
'django.db.models.fields.TextField'
)(
max_length
=
64
)),
))
db
.
send_create_signal
(
u'django_openid_auth'
,
[
'Association'
])
# Adding model 'UserOpenID'
db
.
create_table
(
u'django_openid_auth_useropenid'
,
(
(
u'id'
,
self
.
gf
(
'django.db.models.fields.AutoField'
)(
primary_key
=
True
)),
(
'user'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
to
=
orm
[
'auth.User'
])),
(
'claimed_id'
,
self
.
gf
(
'django.db.models.fields.TextField'
)(
unique
=
True
,
max_length
=
2047
)),
(
'display_id'
,
self
.
gf
(
'django.db.models.fields.TextField'
)(
max_length
=
2047
)),
))
db
.
send_create_signal
(
u'django_openid_auth'
,
[
'UserOpenID'
])
def
backwards
(
self
,
orm
):
# Deleting model 'Nonce'
db
.
delete_table
(
u'django_openid_auth_nonce'
)
# Deleting model 'Association'
db
.
delete_table
(
u'django_openid_auth_association'
)
# Deleting model 'UserOpenID'
db
.
delete_table
(
u'django_openid_auth_useropenid'
)
models
=
{
u'auth.group'
:
{
'Meta'
:
{
'object_name'
:
'Group'
},
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'80'
}),
'permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
u"orm['auth.Permission']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
})
},
u'auth.permission'
:
{
'Meta'
:
{
'ordering'
:
"(u'content_type__app_label', u'content_type__model', u'codename')"
,
'unique_together'
:
"((u'content_type', u'codename'),)"
,
'object_name'
:
'Permission'
},
'codename'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'content_type'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['contenttypes.ContentType']"
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'50'
})
},
u'auth.user'
:
{
'Meta'
:
{
'object_name'
:
'User'
},
'date_joined'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'email'
:
(
'django.db.models.fields.EmailField'
,
[],
{
'max_length'
:
'75'
,
'blank'
:
'True'
}),
'first_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'groups'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
u"orm['auth.Group']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'is_active'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'is_staff'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'is_superuser'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'last_login'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'last_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'password'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'128'
}),
'user_permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
u"orm['auth.Permission']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
'username'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'30'
})
},
u'contenttypes.contenttype'
:
{
'Meta'
:
{
'ordering'
:
"('name',)"
,
'unique_together'
:
"(('app_label', 'model'),)"
,
'object_name'
:
'ContentType'
,
'db_table'
:
"'django_content_type'"
},
'app_label'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'model'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
})
},
u'django_openid_auth.association'
:
{
'Meta'
:
{
'object_name'
:
'Association'
},
'assoc_type'
:
(
'django.db.models.fields.TextField'
,
[],
{
'max_length'
:
'64'
}),
'handle'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'255'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'issued'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'lifetime'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'secret'
:
(
'django.db.models.fields.TextField'
,
[],
{
'max_length'
:
'255'
}),
'server_url'
:
(
'django.db.models.fields.TextField'
,
[],
{
'max_length'
:
'2047'
})
},
u'django_openid_auth.nonce'
:
{
'Meta'
:
{
'object_name'
:
'Nonce'
},
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'salt'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'40'
}),
'server_url'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'2047'
}),
'timestamp'
:
(
'django.db.models.fields.IntegerField'
,
[],
{})
},
u'django_openid_auth.useropenid'
:
{
'Meta'
:
{
'object_name'
:
'UserOpenID'
},
'claimed_id'
:
(
'django.db.models.fields.TextField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'2047'
}),
'display_id'
:
(
'django.db.models.fields.TextField'
,
[],
{
'max_length'
:
'2047'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['auth.User']"
})
}
}
complete_apps
=
[
'django_openid_auth'
]
\ No newline at end of file
django_openid_auth/migrations/0002_add_perm_account_verified.py
→
django_openid_auth/
south_
migrations/0002_add_perm_account_verified.py
View file @
63b625b3
File moved
django_openid_auth/south_migrations/__init__.py
0 → 100644
View file @
63b625b3
django_openid_auth/store.py
View file @
63b625b3
...
...
@@ -27,6 +27,8 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from
__future__
import
unicode_literals
import
base64
import
time
...
...
@@ -38,8 +40,10 @@ from django_openid_auth.models import Association, Nonce
class
DjangoOpenIDStore
(
OpenIDStore
):
def
__init__
(
self
):
self
.
max_nonce_age
=
6
*
60
*
60
# Six hours
super
(
DjangoOpenIDStore
,
self
)
.
__init__
()
self
.
max_nonce_age
=
6
*
60
*
60
# Six hours
def
storeAssociation
(
self
,
server_url
,
association
):
try
:
...
...
django_openid_auth/teams.py
View file @
63b625b3
...
...
@@ -64,31 +64,30 @@ will be provided:
@since: 2.1.1
"""
from
openid.message
import
registerNamespaceAlias
,
\
NamespaceAliasRegistrationError
from
openid.extension
import
Extension
from
openid
import
oidutil
from
__future__
import
unicode_literals
try
:
basestring
#pylint:disable-msg=W0104
except
NameError
:
# For Python 2.2
basestring
=
(
str
,
unicode
)
#pylint:disable-msg=W0622
from
openid
import
oidutil
from
openid.extension
import
Extension
from
openid.message
import
(
registerNamespaceAlias
,
NamespaceAliasRegistrationError
,
)
__all__
=
[
'TeamsRequest'
,
'TeamsResponse'
,
'ns_uri'
,
'supportsTeams'
,
]
]
ns_uri
=
'http://ns.launchpad.net/2007/openid-teams'
try
:
registerNamespaceAlias
(
ns_uri
,
'lp'
)
except
NamespaceAliasRegistrationError
,
e
:
oidutil
.
log
(
'registerNamespaceAlias(
%
r,
%
r) failed:
%
s'
%
(
ns_uri
,
'lp'
,
str
(
e
),))
oidutil
.
log
(
'registerNamespaceAlias(
%
r,
%
r) failed:
%
s'
%
(
ns_uri
,
'lp'
,
str
(
e
)))
def
supportsTeams
(
endpoint
):
"""Does the given endpoint advertise support for Launchpad Teams?
...
...
@@ -101,6 +100,7 @@ def supportsTeams(endpoint):
"""
return
endpoint
.
usesExtension
(
ns_uri
)
class
TeamsNamespaceError
(
ValueError
):
"""The Launchpad teams namespace was not found and could not
be created using the expected name (there's another extension
...
...
@@ -115,6 +115,7 @@ class TeamsNamespaceError(ValueError):
the message that is being processed.
"""
def
getTeamsNS
(
message
):
"""Extract the Launchpad teams namespace URI from the given
OpenID message.
...
...
@@ -145,7 +146,8 @@ def getTeamsNS(message):
# we know that ns_uri defined, because it's defined in the
# else clause of the loop as well, so disable the warning
return
ns_uri
#pylint:disable-msg=W0631
return
ns_uri
class
TeamsRequest
(
Extension
):
"""An object to hold the state of a Launchpad teams request.
...
...
@@ -154,7 +156,8 @@ class TeamsRequest(Extension):
names that the RP is interested in.
@type required: [str]
@group Consumer: requestField, requestTeams, getExtensionArgs, addToOpenIDRequest
@group Consumer: requestField, requestTeams, getExtensionArgs,
addToOpenIDRequest
@group Server: fromOpenIDRequest, parseExtensionArgs
"""
...
...
@@ -308,6 +311,7 @@ class TeamsRequest(Extension):
return
args
class
TeamsResponse
(
Extension
):
"""Represents the data returned in a Launchpad teams response
inside of an OpenID C{id_res} response. This object will be
...
...
@@ -394,7 +398,6 @@ class TeamsResponse(Extension):
if
"is_member"
in
args
:
is_member_str
=
args
[
"is_member"
]
self
.
is_member
=
is_member_str
.
split
(
','
)
#self.is_member = args["is_member"]
return
self
...
...
@@ -406,6 +409,5 @@ class TeamsResponse(Extension):
@see: openid.extension
"""
ns_args
=
{
'is_member'
:
','
.
join
(
self
.
is_member
)
,
}
ns_args
=
{
'is_member'
:
','
.
join
(
self
.
is_member
)}
return
ns_args
django_openid_auth/tests/__init__.py
View file @
63b625b3
...
...
@@ -26,18 +26,8 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import
unittest
from
test_views
import
*
from
test_settings
import
*
from
test_store
import
*
from
test_auth
import
*
from
test_admin
import
*
def
suite
():
suite
=
unittest
.
TestSuite
()
for
name
in
[
'test_auth'
,
'test_models'
,
'test_settings'
,
'test_store'
,
'test_views'
,
'test_admin'
]:
mod
=
__import__
(
'
%
s.
%
s'
%
(
__name__
,
name
),
{},
{},
[
'suite'
])
suite
.
addTest
(
mod
.
suite
())
return
suite
from
.test_views
import
*
# flake8: noqa
from
.test_settings
import
*
from
.test_store
import
*
from
.test_auth
import
*
from
.test_admin
import
*
django_openid_auth/tests/helpers.py
View file @
63b625b3
from
__future__
import
unicode_literals
from
django.test.utils
import
override_settings
...
...
django_openid_auth/tests/test_admin.py
View file @
63b625b3
...
...
@@ -25,35 +25,19 @@
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
"""
Tests for the django_openid_auth Admin login form replacement.
"""
import
unittest
"""Tests for the django_openid_auth Admin login form replacement."""
from
django.conf
import
settings
from
django.contrib.auth.models
import
User
,
AnonymousUser
from
__future__
import
unicode_literals
settings
.
OPENID_USE_AS_ADMIN_LOGIN
=
True
from
django.conf
import
settings
from
django.contrib.auth.models
import
User
from
django.test
import
TestCase
from
django.test.utils
import
override_settings
def
create_user
(
is_staff
=
False
,
authenticated
=
True
):
"""
Create and return a user, either the AnonymousUser or a normal Django user,
setting the is_staff attribute if appropriate.
"""
if
not
authenticated
:
return
AnonymousUser
()
else
:
user
=
User
(
username
=
u'testing'
,
email
=
'testing@example.com'
,
is_staff
=
is_staff
)
user
.
set_password
(
u'test'
)
user
.
save
()
@override_settings
(
OPENID_USE_AS_ADMIN_LOGIN
=
True
)
class
SiteAdminTests
(
TestCase
):
"""
TestCase for accessing /admin/ when the django_openid_auth form replacement
...
...
@@ -65,23 +49,21 @@ class SiteAdminTests(TestCase):
If the request has an authenticated user, who is not flagged as a
staff member, then they get a failure response.
"""
create_user
()
self
.
client
.
login
(
username
=
'testing'
,
password
=
'test'
)
response
=
self
.
client
.
get
(
'/admin/'
)
self
.
assertTrue
(
'User testing does not have admin access.'
in
response
.
content
,
'Missing error message in response'
)
User
.
objects
.
create_user
(
username
=
'testing'
,
email
=
'testing@example.com'
,
password
=
'test'
)
assert
self
.
client
.
login
(
username
=
'testing'
,
password
=
'test'
)
response
=
self
.
client
.
get
(
'/admin/'
,
follow
=
True
)
self
.
assertContains
(
response
,
'User testing does not have admin/staff access.'
,
status_code
=
403
)
def
test_admin_site_with_openid_login_non_authenticated_user
(
self
):
"""
Unauthenticated users accessing the admin page should be directed to
the OpenID login url.
"""
response
=
self
.
client
.
get
(
'/admin/'
)
self
.
assertEqual
(
302
,
response
.
status_code
)
self
.
assertEqual
(
'http://testserver'
+
getattr
(
settings
,
'LOGIN_URL'
,
'/openid/login'
)
+
'?next=/admin/'
,
response
[
'Location'
])
def
suite
():
return
unittest
.
TestLoader
()
.
loadTestsFromName
(
__name__
)
response
=
self
.
client
.
get
(
'/admin/'
,
follow
=
True
)
self
.
assertRedirects
(
response
,
getattr
(
settings
,
'LOGIN_URL'
,
'/openid/login'
)
+
'?next=
%2
Fadmin
%2
F'
)
django_openid_auth/tests/test_auth.py
View file @
63b625b3
This diff is collapsed.
Click to expand it.
django_openid_auth/tests/test_models.py
View file @
63b625b3
...
...
@@ -26,7 +26,7 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import
unittest
from
__future__
import
unicode_literals
from
django.contrib.auth.models
import
User
from
django.test
import
TestCase
...
...
@@ -72,7 +72,3 @@ class UserOpenIDModelTestCase(TestCase):
self
.
assertFalse
(
User
.
objects
.
get
(
username
=
'someuser'
)
.
has_perm
(
'django_openid_auth.account_verified'
))
def
suite
():
return
unittest
.
TestLoader
()
.
loadTestsFromName
(
__name__
)
django_openid_auth/tests/test_settings.py
View file @
63b625b3
from
unittest
import
skipIf
,
TestLoader
# django-openid-auth - OpenID integration for django.contrib.auth
#
# Copyright (C) 2013 Canonical Ltd.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from
__future__
import
unicode_literals
from
unittest
import
skipIf
from
django
import
VERSION
from
django.conf
import
settings
...
...
@@ -16,20 +46,9 @@ class SessionSerializerTest(TestCase):
[0] https://bit.ly/1myzetd
[1] https://github.com/openid/python-openid/issues/17
"""
@skipIf
(
VERSION
>=
(
1
,
6
,
0
),
"Old versions used the pickle serializer."
)
def
test_not_using_json_session_serializer
(
self
):
# We use getattr because this setting did not exist in Django
# 1.4 (pickle serialization was hard coded)
serializer
=
getattr
(
settings
,
'SESSION_SERIALIZER'
,
''
)
self
.
assertNotEqual
(
serializer
,
'django.contrib.sessions.serializers.JSONSerializer'
)
@skipIf
(
VERSION
<
(
1
,
6
,
0
),
"Newer versions use JSON by default.
"
)
def
test_using_
json
_session_serializer
(
self
):
@skipIf
(
VERSION
<
(
1
,
5
),
"Django 1.4 does not provide SESSION_SERIALIZER
"
)
def
test_using_
pickle
_session_serializer
(
self
):
serializer
=
getattr
(
settings
,
'SESSION_SERIALIZER'
,
''
)
self
.
assertEqual
(
serializer
,
'django.contrib.sessions.serializers.JSONSerializer'
)
def
suite
():
return
TestLoader
()
.
loadTestsFromName
(
__name__
)
serializer
,
'django.contrib.sessions.serializers.PickleSerializer'
)
django_openid_auth/tests/test_store.py
View file @
63b625b3
...
...
@@ -26,8 +26,9 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from
__future__
import
unicode_literals
import
time
import
unittest
from
django.test
import
TestCase
from
openid.association
import
Association
as
OIDAssociation
...
...
@@ -187,7 +188,3 @@ class OpenIDStoreTests(TestCase):
# The second (non-expired) association is left behind.
self
.
assertNotEqual
(
self
.
store
.
getAssociation
(
'server-url'
,
'handle2'
),
None
)
def
suite
():
return
unittest
.
TestLoader
()
.
loadTestsFromName
(
__name__
)
django_openid_auth/tests/test_views.py
View file @
63b625b3
This diff is collapsed.
Click to expand it.
django_openid_auth/tests/urls.py
View file @
63b625b3
...
...
@@ -26,14 +26,18 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from
__future__
import
unicode_literals
from
django.conf.urls
import
patterns
,
include
from
django.http
import
HttpResponse
from
django.conf.urls
import
*
def
get_user
(
request
):
return
HttpResponse
(
request
.
user
.
username
)
urlpatterns
=
patterns
(
''
,
urlpatterns
=
patterns
(
''
,
(
r'^getuser/$'
,
get_user
),
(
r'^openid/'
,
include
(
'django_openid_auth.urls'
)),
)
django_openid_auth/urls.py
View file @
63b625b3
...
...
@@ -27,9 +27,12 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from
django.conf.urls
import
*
from
__future__
import
unicode_literals
urlpatterns
=
patterns
(
'django_openid_auth.views'
,
from
django.conf.urls
import
patterns
,
url
urlpatterns
=
patterns
(
'django_openid_auth.views'
,
url
(
r'^login/$'
,
'login_begin'
,
name
=
'openid-login'
),
url
(
r'^complete/$'
,
'login_complete'
,
name
=
'openid-complete'
),
url
(
r'^logo.gif$'
,
'logo'
,
name
=
'openid-logo'
),
...
...
django_openid_auth/views.py
View file @
63b625b3
...
...
@@ -27,6 +27,8 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from
__future__
import
unicode_literals
import
re
import
urllib
from
urlparse
import
urlsplit
...
...
@@ -62,6 +64,7 @@ from django_openid_auth.exceptions import (
next_url_re
=
re
.
compile
(
'^/[-
\
w/]+$'
)
def
is_valid_next_url
(
next
):
# When we allow this:
# /openid/?next=/welcome/
...
...
@@ -78,8 +81,8 @@ def sanitise_redirect_url(redirect_to):
is_valid
=
False
elif
'//'
in
redirect_to
:
# Allow the redirect URL to be external if it's a permitted domain
allowed_domains
=
getattr
(
settings
,
"ALLOWED_EXTERNAL_OPENID_REDIRECT_DOMAINS"
,
[])
allowed_domains
=
getattr
(
settings
,
"ALLOWED_EXTERNAL_OPENID_REDIRECT_DOMAINS"
,
[])
s
,
netloc
,
p
,
q
,
f
=
urlsplit
(
redirect_to
)
# allow it if netloc is blank or if the domain is allowed
if
netloc
:
...
...
@@ -113,11 +116,13 @@ def render_openid_request(request, openid_request, return_to, trust_root=None):
if
openid_request
.
shouldSendRedirect
():
redirect_url
=
openid_request
.
redirectURL
(
trust_root
,
return_to
)
re
turn
HttpResponseRedirect
(
redirect_url
)
re
sponse
=
HttpResponseRedirect
(
redirect_url
)
else
:
form_html
=
openid_request
.
htmlMarkup
(
trust_root
,
return_to
,
form_tag_attrs
=
{
'id'
:
'openid_message'
})
return
HttpResponse
(
form_html
,
content_type
=
'text/html;charset=UTF-8'
)
response
=
HttpResponse
(
form_html
,
content_type
=
'text/html;charset=UTF-8'
)
return
response
def
default_render_failure
(
request
,
message
,
status
=
403
,
...
...
@@ -133,7 +138,7 @@ def default_render_failure(request, message, status=403,
def
parse_openid_response
(
request
):
"""Parse an OpenID response from a Django request."""
# Short cut if there is no request parameters.
#if len(request.REQUEST) == 0:
#
if len(request.REQUEST) == 0:
# return None
current_url
=
request
.
build_absolute_uri
()
...
...
@@ -164,15 +169,15 @@ def login_begin(request, template_name='openid/login.html',
# Invalid or no form data:
if
openid_url
is
None
:
return
render_to_response
(
template_name
,
{
'form'
:
login_form
,
redirect_field_name
:
redirect_to
},
context_instance
=
RequestContext
(
request
))
context
=
{
'form'
:
login_form
,
redirect_field_name
:
redirect_to
}
return
render_to_response
(
template_name
,
context
,
context_instance
=
RequestContext
(
request
))
consumer
=
make_consumer
(
request
)
try
:
openid_request
=
consumer
.
begin
(
openid_url
)
except
DiscoveryFailure
,
exc
:
except
DiscoveryFailure
as
exc
:
return
render_failure
(
request
,
"OpenID discovery error:
%
s"
%
(
str
(
exc
),),
status
=
500
,
exception
=
exc
)
...
...
@@ -222,11 +227,11 @@ def login_begin(request, template_name='openid/login.html',
sreg_optional_fields
.
extend
(
getattr
(
settings
,
'OPENID_SREG_EXTRA_FIELDS'
,
[]))
sreg_optional_fields
=
[
field
for
field
in
sreg_optional_fields
if
(
not
field
in
sreg_required_fields
)
]
field
for
field
in
sreg_optional_fields
if
field
not
in
sreg_required_fields
]
openid_request
.
addExtension
(
sreg
.
SRegRequest
(
optional
=
sreg_optional_fields
,
required
=
sreg_required_fields
))
required
=
sreg_required_fields
))
if
getattr
(
settings
,
'OPENID_PHYSICAL_MULTIFACTOR_REQUIRED'
,
False
):
preferred_auth
=
[
...
...
@@ -236,13 +241,16 @@ def login_begin(request, template_name='openid/login.html',
openid_request
.
addExtension
(
pape_request
)
# Request team info
teams_mapping_auto
=
getattr
(
settings
,
'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO'
,
False
)
teams_mapping_auto_blacklist
=
getattr
(
settings
,
'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO_BLACKLIST'
,
[])
teams_mapping_auto
=
getattr
(
settings
,
'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO'
,
False
)
teams_mapping_auto_blacklist
=
getattr
(
settings
,
'OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO_BLACKLIST'
,
[])
launchpad_teams
=
getattr
(
settings
,
'OPENID_LAUNCHPAD_TEAMS_MAPPING'
,
{})
if
teams_mapping_auto
:
#ignore launchpad teams. use all django-groups
#
ignore launchpad teams. use all django-groups
launchpad_teams
=
dict
()
all_groups
=
Group
.
objects
.
exclude
(
name__in
=
teams_mapping_auto_blacklist
)
all_groups
=
Group
.
objects
.
exclude
(
name__in
=
teams_mapping_auto_blacklist
)
for
group
in
all_groups
:
launchpad_teams
[
group
.
name
]
=
group
.
name
...
...
@@ -270,9 +278,9 @@ def login_begin(request, template_name='openid/login.html',
def
login_complete
(
request
,
redirect_field_name
=
REDIRECT_FIELD_NAME
,
render_failure
=
None
):
redirect_to
=
request
.
REQUEST
.
get
(
redirect_field_name
,
''
)
render_failure
=
render_failure
or
\
getattr
(
settings
,
'OPENID_RENDER_FAILURE'
,
None
)
or
\
default_render_failure
render_failure
=
(
render_failure
or
getattr
(
settings
,
'OPENID_RENDER_FAILURE'
,
None
)
or
default_render_failure
)
openid_response
=
parse_openid_response
(
request
)
if
not
openid_response
:
...
...
@@ -288,10 +296,12 @@ def login_complete(request, redirect_field_name=REDIRECT_FIELD_NAME,
if
user
is
not
None
:
if
user
.
is_active
:
auth_login
(
request
,
user
)
response
=
HttpResponseRedirect
(
sanitise_redirect_url
(
redirect_to
))
response
=
HttpResponseRedirect
(
sanitise_redirect_url
(
redirect_to
))
# Notify any listeners that we successfully logged in.
openid_login_complete
.
send
(
sender
=
UserOpenID
,
request
=
request
,
openid_login_complete
.
send
(
sender
=
UserOpenID
,
request
=
request
,
openid_response
=
openid_response
)
return
response
...
...
example_consumer/settings.py
View file @
63b625b3
...
...
@@ -27,91 +27,44 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# Django settings for example project.
import
django
django_version
=
django
.
get_version
()
DEBUG
=
True
TEMPLATE_DEBUG
=
DEBUG
"""
Django settings for example_consumer project.
ADMINS
=
(
# ('Your Name', 'your_email@domain.com'),
)
For more information on this file, see
https://docs.djangoproject.com/en/1.7/topics/settings/
MANAGERS
=
ADMINS
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.7/ref/settings/
"""
if
django_version
>=
"1.2"
:
csrf_middleware
=
'django.middleware.csrf.CsrfViewMiddleware'
DATABASES
=
{
'default'
:
{
'ENGINE'
:
'django.db.backends.sqlite3'
,
'NAME'
:
'sqlite.db'
,
}
}
TEMPLATE_LOADERS
=
(
'django.template.loaders.filesystem.Loader'
,
'django.template.loaders.app_directories.Loader'
,
)
else
:
csrf_middleware
=
'django.contrib.csrf.middleware.CsrfViewMiddleware'
TEMPLATE_LOADERS
=
(
'django.template.loaders.filesystem.load_template_source'
,
'django.template.loaders.app_directories.load_template_source'
,
)
DATABASE_ENGINE
=
'sqlite3'
# 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'ado_mssql'.
DATABASE_NAME
=
'sqlite.db'
# Or path to database file if using sqlite3.
DATABASE_USER
=
''
# Not used with sqlite3.
DATABASE_PASSWORD
=
''
# Not used with sqlite3.
DATABASE_HOST
=
''
# Set to empty string for localhost. Not used with sqlite3.
DATABASE_PORT
=
''
# Set to empty string for default. Not used with sqlite3.
# Local time zone for this installation. Choices can be found here:
# http://www.postgresql.org/docs/8.1/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE
# although not all variations may be possible on all operating systems.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE
=
'America/Chicago'
# Language code for this installation. All choices can be found here:
# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
# http://blogs.law.harvard.edu/tech/stories/storyReader$15
LANGUAGE_CODE
=
'en-us'
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import
os
import
django
SITE_ID
=
1
BASE_DIR
=
os
.
path
.
dirname
(
os
.
path
.
dirname
(
__file__
))
# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N
=
True
# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT
=
''
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY
=
'34958734985734985734985798437'
# URL that handles the media served from MEDIA_ROOT.
# Example: "http://media.lawrence.com"
MEDIA_URL
=
''
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG
=
True
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX
=
'/media/'
TEMPLATE_DEBUG
=
True
# Make this unique, and don't share it with anybody.
SECRET_KEY
=
'34958734985734985734985798437'
ALLOWED_HOSTS
=
[]
MIDDLEWARE_CLASSES
=
(
'django.middleware.common.CommonMiddleware'
,
'django.contrib.sessions.middleware.SessionMiddleware'
,
'django.contrib.auth.middleware.AuthenticationMiddleware'
,
csrf_middleware
,
'django.middleware.csrf.CsrfViewMiddleware'
,
)
ROOT_URLCONF
=
'example_consumer.urls'
TEMPLATE_DIRS
=
(
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
# Application definition
INSTALLED_APPS
=
(
'django.contrib.auth'
,
...
...
@@ -119,9 +72,46 @@ INSTALLED_APPS = (
'django.contrib.sessions'
,
'django.contrib.admin'
,
'django_openid_auth'
,
'south'
,
)
if
django
.
VERSION
<
(
1
,
7
):
INSTALLED_APPS
+=
(
'south'
,)
ROOT_URLCONF
=
'example_consumer.urls'
WSGI_APPLICATION
=
'example_consumer.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases
DATABASES
=
{
'default'
:
{
'ENGINE'
:
'django.db.backends.sqlite3'
,
'NAME'
:
os
.
path
.
join
(
BASE_DIR
,
'db.sqlite3'
),
}
}
# Internationalization
# https://docs.djangoproject.com/en/1.7/topics/i18n/
LANGUAGE_CODE
=
'en-us'
TIME_ZONE
=
'UTC'
USE_I18N
=
True
USE_TZ
=
True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.7/howto/static-files/
STATIC_URL
=
'/static/'
# the library python-openid does not support a json session serializer
# <openid.yadis.manager.YadisServiceManager> is not JSON serializable
# https://github.com/openid/python-openid/issues/17
SESSION_SERIALIZER
=
'django.contrib.sessions.serializers.PickleSerializer'
AUTHENTICATION_BACKENDS
=
(
'django_openid_auth.auth.OpenIDBackend'
,
'django.contrib.auth.backends.ModelBackend'
,
...
...
@@ -144,7 +134,7 @@ OPENID_VALID_VERIFICATION_SCHEMES = {
# If set, always use this as the identity URL rather than asking the
# user. This only makes sense if it is a server URL.
OPENID_SSO_SERVER_URL
=
'https://login.
launchpad.net
/'
OPENID_SSO_SERVER_URL
=
'https://login.
ubuntu.com
/'
# Tell django.contrib.auth to use the OpenID signin URLs.
LOGIN_URL
=
'/openid/login/'
...
...
example_consumer/urls.py
View file @
63b625b3
...
...
@@ -27,7 +27,7 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from
django.conf.urls
import
*
from
django.conf.urls
import
patterns
,
include
,
url
from
django.contrib
import
admin
import
views
...
...
@@ -35,11 +35,12 @@ import views
admin
.
autodiscover
()
urlpatterns
=
patterns
(
''
,
(
r'^$'
,
views
.
index
),
(
r'^openid/'
,
include
(
'django_openid_auth.urls'
)),
(
r'^logout/$'
,
'django.contrib.auth.views.logout'
),
(
r'^private/$'
,
views
.
require_authentication
),
urlpatterns
=
patterns
(
''
,
url
(
r'^$'
,
views
.
index
),
url
(
r'^openid/'
,
include
(
'django_openid_auth.urls'
)),
url
(
r'^logout/$'
,
'django.contrib.auth.views.logout'
),
url
(
r'^private/$'
,
views
.
require_authentication
),
(
r'^admin/'
,
include
(
admin
.
site
.
urls
)),
url
(
r'^admin/'
,
include
(
admin
.
site
.
urls
)),
)
example_consumer/wsgi.py
0 → 100644
View file @
63b625b3
"""
WSGI config for demo project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
"""
import
os
os
.
environ
.
setdefault
(
"DJANGO_SETTINGS_MODULE"
,
"demo.settings"
)
from
django.core.wsgi
import
get_wsgi_application
application
=
get_wsgi_application
()
example_consumer/
manage.py
→
manage.py
View file @
63b625b3
...
...
@@ -3,7 +3,7 @@ import os
import
sys
if
__name__
==
"__main__"
:
os
.
environ
.
setdefault
(
"DJANGO_SETTINGS_MODULE"
,
"settings"
)
os
.
environ
.
setdefault
(
"DJANGO_SETTINGS_MODULE"
,
"
example_consumer.
settings"
)
from
django.core.management
import
execute_from_command_line
...
...
setup.py
View file @
63b625b3
...
...
@@ -43,7 +43,7 @@ from setuptools import find_packages, setup
description
,
long_description
=
__doc__
.
split
(
'
\n\n
'
,
1
)
VERSION
=
'0.
5.1
'
VERSION
=
'0.
6
'
setup
(
name
=
'django-openid-auth'
,
...
...
tox.ini
View file @
63b625b3
[tox]
envlist
=
py2.7-django1.4,
py2.7-django1.5,
py2.7-django1.6
py2.7-django1.4,
py2.7-django1.5,
py2.7-django1.6,
py2.7-django1.7,
py2.7-django1.8
[testenv]
commands
=
make check
commands
=
python manage.py test django_openid_auth
deps
=
mock
python-openid
# Python 2.7
[testenv:py2.7-django1.4]
basepython
=
python2.7
deps
=
django >= 1.4, < 1.5
python-openid
south
deps
=
django
>=
1.4,
<
1.5
{
[testenv]
deps}
south
=
=1.0
[testenv:py2.7-django1.5]
basepython
=
python2.7
deps
=
django >= 1.5, < 1.6
python-openid
south
deps
=
django
>=
1.5,
<
1.6
{
[testenv]
deps}
south
=
=1.0
[testenv:py2.7-django1.6]
basepython
=
python2.7
deps
=
django >= 1.6, < 1.7
python-openid
south
deps
=
django
>=
1.6,
<
1.7
{
[testenv]
deps}
south
=
=1.0
[testenv:py2.7-django1.7]
basepython
=
python2.7
deps
=
django
>=
1.7,
<
1.8
{
[testenv]
deps}
[testenv:py2.7-django1.8]
basepython
=
python2.7
deps
=
django
>=
1.8,
<
1.9
{
[testenv]
deps}
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