Skip to content

Commit

Permalink
- OIDC 1.0 compliancy preparation: add api > UserInfo method
Browse files Browse the repository at this point in the history
  • Loading branch information
afabiani committed Jun 4, 2018
1 parent 73b949f commit e7ddf9a
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 19 deletions.
98 changes: 90 additions & 8 deletions geonode/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@

from guardian.models import Group

from allauth.account.utils import user_field, user_email, user_username

from ..utils import json_response


def verify_access_token(key):
try:
Expand All @@ -54,6 +58,67 @@ def get_client_ip(request):
return ip


def extract_headers(request):
"""
Extracts headers from the Django request object
:param request: The current django.http.HttpRequest object
:return: a dictionary with OAuthLib needed headers
"""
headers = request.META.copy()
if "wsgi.input" in headers:
del headers["wsgi.input"]
if "wsgi.errors" in headers:
del headers["wsgi.errors"]
if "HTTP_AUTHORIZATION" in headers:
headers["Authorization"] = headers["HTTP_AUTHORIZATION"]

return headers


@csrf_exempt
def user_info(request):
headers = extract_headers(request)
user = request.user

if not user:
out = {'success': False,
'status': 'error',
'errors': {'user': ['User is not authenticated']}
}
return json_response(out, status=401)

if 'Authorization' not in headers and 'Bearer' not in headers["Authorization"]:
out = {'success': False,
'status': 'error',
'errors': {'auth': ['No token provided.']}
}
return json_response(out, status=403)

groups = [group.name for group in user.groups.all()]
if user.is_superuser:
groups.append("admin")

user_info = json.dumps({
"sub": str(user.id),
"name": " ".join([user_field(user, 'first_name'), user_field(user, 'last_name')]),
"given_name": user_field(user, 'first_name'),
"family_name": user_field(user, 'last_name'),
"email": user_email(user),
"preferred_username": user_username(user),
"groups": groups
})

print(" >>>>>>>>>>>>>>>>>>>>>>>>>> user_info %s " % user_info)

response = HttpResponse(
user_info,
content_type="application/json"
)
response['Cache-Control'] = 'no-store'
response['Pragma'] = 'no-cache'
return response


@csrf_exempt
def verify_token(request):
"""
Expand All @@ -74,9 +139,11 @@ def verify_token(request):
)
"""

if (request.POST and request.POST['token']):
if (request.POST and 'token' in request.POST):
token = None
try:
token = verify_access_token(request.POST['token'])
access_token = request.POST.get('token')
token = verify_access_token(access_token)
except Exception as e:
return HttpResponse(
json.dumps({
Expand All @@ -86,18 +153,33 @@ def verify_token(request):
content_type="application/json"
)

return HttpResponse(
json.dumps({
if token:
token_info = json.dumps({
'client_id': token.application.client_id,
'issued_to': token.user.username,
'user_id': token.user.id,
'username': token.user.username,
'issued_to': token.user.username,
'access_token': access_token,
'email': token.user.email,
'verified_email': 'true',
'access_type': 'online',
'expires_in': (token.expires - timezone.now()).total_seconds() * 1000
}),
content_type="application/json"
)
})

response = HttpResponse(
token_info,
content_type="application/json"
)
response["Authorization"] = ("Bearer %s" % access_token)
return response
else:
return HttpResponse(
json.dumps({
'error': 'No access_token from server.'
}),
status=403,
content_type="application/json"
)

return HttpResponse(
json.dumps({
Expand Down
5 changes: 5 additions & 0 deletions geonode/base/management/commands/updategeoip.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ def handle(self, *args, **options):
self.handle_old_format(open('output.bin', 'r'), fname)
else:
self.handle_new_format(open('output.bin', 'r'), fname)
try:
# Cleaning up
os.remove('output.bin')
except OSError:
pass


def handle_new_format(self, f, fname):
Expand Down
22 changes: 21 additions & 1 deletion geonode/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -569,14 +569,34 @@

OAUTH2_PROVIDER = {
'SCOPES': {
'openid': 'Default to OpenID',
'read': 'Read scope',
'write': 'Write scope',
'groups': 'Access to your groups'
},

'CLIENT_ID_GENERATOR_CLASS': 'oauth2_provider.generators.ClientIdGenerator',
# 'OAUTH2_VALIDATOR_CLASS': 'geonode.security.oauth2_validators.OIDCValidator',

# OpenID Connect
# "OIDC_ISS_ENDPOINT": "http://localhost:8000",
# "OIDC_USERINFO_ENDPOINT": "http://localhost:8000/api/o/v4/tokeninfo/",
"OIDC_RSA_PRIVATE_KEY": b"""-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCIThjbTwpYu4Lwqp8oA7PqD6Ij/GwpLFJuPbWVaeCDaX6T7mh8
mJMIEgl/VIZasLH8SwU5mZ4sPeiqk7NgJq1XDo97q5mlFoNVHMCH38KQzSIBWtbq
WnEEnQdiqBbCmmIebLd4OcfpbIVUI89cnCq7U0M1ie0KOopWSHWOP6/35QIDAQAB
AoGBAIdwmtBotM5A3LaJxAY9z6uXhzSc4Vj0OqBiXymtgDL0Q5t4/Yg5D3ioe5lz
guFgzCr23KVEmOA7UBMXGtlC9V+iizVSbF4g2GqPLBKk+IYcAhfbSCg5rbbtQ5m2
PZxKZlJOQnjFLeh4sxitd84GfX16RfAhsvIiaN4d4CG+RAlhAkEA1Vitep0aHKmA
KRIGvZrgfH7uEZh2rRsCoo9lTxCT8ocCU964iEUxNH050yKdqYzVnNyFysY7wFgL
gsVzPROE6QJBAKOOWj9mN7uxhjRv2L4iYJ/rZaloVA49KBZEhvI+PgC5kAIrNVaS
n1kbJtFg54IS8HsYIP4YxONLqmDuhZL2rZ0CQQDId9wCo85eclMPxHV7AiXANdDj
zbxt6jxunYlXYr9yG7RvNI921HVo2eZU42j8YW5zR6+cGusYUGL4jSo8kLPJAkAG
SLPi97Rwe7OiVCHJvFxmCI9RYPbJzUO7B0sAB7AuKvMDglF8UAnbTJXDOavrbXrb
3+N0n9MAwKl9K+zp5pxpAkBSEUlYA0kDUqRgfuAXrrO/JYErGzE0UpaHxq5gCvTf
g+gp5fQ4nmDrSNHjakzQCX2mKMsx/GLWZzoIDd7ECV9f
-----END RSA PRIVATE KEY-----"""
}

# authorized exempt urls needed for oauth when GeoNode is set to lockdown
AUTH_EXEMPT_URLS = ('/api/o/*', '/api/roles', '/api/adminRole', '/api/users',)

Expand Down
2 changes: 1 addition & 1 deletion geonode/static/geonode/js/upload/LayerInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ define(function (require, exports) {
$(this).text('Done').attr('disabled','disabled');
var id = (new Date()).getTime();
var newWin = window.open(window.location.href,
id, "toolbar=1,scrollbars=1,location=0,statusbar=0,menubar=1,resizable=1,width=800,height=600,left = 240,top = 212");
id, "toolbar=1,scrollbars=1,location=0,statusbar=0,menubar=1,resizable=1,width=1100,height=800,left = 240,top = 100");
common.make_request({
url: event.data.url,
async: true,
Expand Down
4 changes: 3 additions & 1 deletion geonode/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from . import views

from geonode.api.urls import api
from geonode.api.views import verify_token, roles, users, admin_role
from geonode.api.views import verify_token, user_info, roles, users, admin_role

from geonode import geoserver, qgis_server # noqa
from geonode.utils import check_ogc_backend
Expand Down Expand Up @@ -155,6 +155,8 @@
# Api Views
url(r'^api/o/v4/tokeninfo',
verify_token, name='tokeninfo'),
url(r'^api/o/v4/userinfo',
user_info, name='userinfo'),
url(r'^api/roles', roles, name='roles'),
url(r'^api/adminRole', admin_role, name='adminRole'),
url(r'^api/users', users, name='users'),
Expand Down
34 changes: 29 additions & 5 deletions pavement.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,21 +75,45 @@
def grab(src, dest, name):
download = True
if not dest.exists():
print 'Downloading %s' % name
print('Downloading %s' % name)
elif not zipfile.is_zipfile(dest):
print 'Downloading %s (corrupt file)' % name
print('Downloading %s (corrupt file)' % name)
else:
download = False
if download:
if str(src).startswith("file://"):
src2 = src[7:]
if not os.path.exists(src2):
print "Source location (%s) does not exist" % str(src2)
print("Source location (%s) does not exist" % str(src2))
else:
print "Copying local file from %s" % str(src2)
print("Copying local file from %s" % str(src2))
shutil.copyfile(str(src2), str(dest))
else:
urllib.urlretrieve(str(src), str(dest))
# urllib.urlretrieve(str(src), str(dest))
from tqdm import tqdm
import requests
import math
# Streaming, so we can iterate over the response.
r = requests.get(str(src), stream=True, timeout=10)
# Total size in bytes.
total_size = int(r.headers.get('content-length', 0))
print("Requesting %s" % str(src))
block_size = 1024
wrote = 0
with open('output.bin', 'wb') as f:
for data in tqdm(r.iter_content(block_size), total=math.ceil(total_size//block_size) , unit='KB', unit_scale=False):
wrote = wrote + len(data)
f.write(data)
print(" total_size [%d] / wrote [%d] " % (total_size, wrote))
if total_size != 0 and wrote != total_size:
print("ERROR, something went wrong")
else:
shutil.move('output.bin', str(dest))
try:
# Cleaning up
os.remove('output.bin')
except OSError:
pass


@task
Expand Down
6 changes: 3 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,12 @@ django-reversion<=2.0.13 # python-django-reversion (2.0.13 in our ppa)
django-suit<=0.2.26 # python-django-suit (0.2.26 in our ppa)
django-tastypie<=0.14.0 # python-django-tastypie (0.14.0 in our ppa)
django-invitations<=1.9.2 # python-django-invitations (1.9.2 in our ppa)
django-oauth-toolkit>=0.10.0,<1.0 # python-django-oauth-toolkit (0.12.0 in our ppa)
django-oauth-toolkit==1.1.2 # python-django-oauth-toolkit (0.12.0 in our ppa)
# djangorestframework<=3.7.7 # TODO
# djangorestframework-gis<=0.12 # TODO
# drf-nested-routers==0.90.0 # python-drf-nested-routers (0.90.0 in our ppa)
# drf-openapi==1.3.0 # python-drf-openapi (1.3.0 in our ppa)
oauthlib==2.0.1 # python-oauthlib (2.0.6 in our ppa) FIXME
oauthlib==2.1.0 # python-oauthlib (2.0.6 in our ppa) FIXME

# geopython dependencies
pyproj>=1.9.5,<=1.9.5.1 # python-pyproj (1.9.5.1)
Expand Down Expand Up @@ -157,7 +157,7 @@ python-gnupg<=0.4.1 # (0.4.1 in our ppa)
python-mimeparse<=1.6.0 # (1.6.0 in our ppa)
pytz<=2018.3 # python-pytz (2018.3 in our ppa)
regex<=2016.7.21 # (0.1.20160110 in ppa)
requests==2.11.1 # (2.18.4 in our ppa) FIXME
requests==2.18.4 # (2.18.4 in our ppa) FIXME
simplejson<=3.13.2 # (3.13.2 in our ppa)
tablib<=0.12.1 # (0.12.1 in our ppa)
timeout-decorator==0.4.0 # TODO
Expand Down

0 comments on commit e7ddf9a

Please sign in to comment.