From eebcbcd210c4084b8f16c095b0daf7b6fe3db46d Mon Sep 17 00:00:00 2001 From: William Bourque Date: Fri, 17 Jan 2014 18:33:11 +0000 Subject: [PATCH 1/1] HUE-1882. [core] OAuth support for Facebook, Google+ and Linkedin This patch is a reimplementation of oauth. The current implementation only support twitter; this patch add support for Facebook, Google+ and Linkedin as well as Twitter. --- desktop/Makefile | 3 +- desktop/conf.dist/hue.ini | 58 ++++- desktop/conf/pseudo-distributed.ini.tmpl | 59 ++++- desktop/core/src/desktop/settings.py | 7 + desktop/core/src/desktop/urls.py | 5 + desktop/libs/liboauth/Makefile | 36 +++ desktop/libs/liboauth/babel.cfg | 2 + desktop/libs/liboauth/setup.py | 30 +++ desktop/libs/liboauth/src/liboauth/__init__.py | 0 desktop/libs/liboauth/src/liboauth/backend.py | 269 +++++++++++++++++++++ desktop/libs/liboauth/src/liboauth/conf.py | 149 ++++++++++++ .../src/liboauth/locale/en/LC_MESSAGES/django.po | 20 ++ .../libs/liboauth/src/liboauth/locale/en_US.pot | 19 ++ .../liboauth/src/liboauth/static/art/icon-fb.png | Bin 0 -> 1221 bytes .../src/liboauth/static/art/icon-gplus.png | Bin 0 -> 2210 bytes .../src/liboauth/static/art/icon-linkedin.png | Bin 0 -> 1544 bytes .../src/liboauth/static/art/icon-twitter.png | Bin 0 -> 1407 bytes .../src/liboauth/templates/oauth-login.mako | 252 +++++++++++++++++++ desktop/libs/liboauth/src/liboauth/urls.py | 27 +++ desktop/libs/liboauth/src/liboauth/views.py | 89 +++++++ 20 files changed, 1022 insertions(+), 3 deletions(-) create mode 100644 desktop/libs/liboauth/Makefile create mode 100644 desktop/libs/liboauth/babel.cfg create mode 100644 desktop/libs/liboauth/setup.py create mode 100644 desktop/libs/liboauth/src/liboauth/__init__.py create mode 100644 desktop/libs/liboauth/src/liboauth/backend.py create mode 100644 desktop/libs/liboauth/src/liboauth/conf.py create mode 100644 desktop/libs/liboauth/src/liboauth/locale/en/LC_MESSAGES/django.po create mode 100644 desktop/libs/liboauth/src/liboauth/locale/en_US.pot create mode 100644 desktop/libs/liboauth/src/liboauth/static/art/icon-fb.png create mode 100644 desktop/libs/liboauth/src/liboauth/static/art/icon-gplus.png create mode 100644 desktop/libs/liboauth/src/liboauth/static/art/icon-linkedin.png create mode 100644 desktop/libs/liboauth/src/liboauth/static/art/icon-twitter.png create mode 100644 desktop/libs/liboauth/src/liboauth/templates/oauth-login.mako create mode 100644 desktop/libs/liboauth/src/liboauth/urls.py create mode 100644 desktop/libs/liboauth/src/liboauth/views.py diff --git a/desktop/Makefile b/desktop/Makefile index 8ff9744..0417785 100644 --- a/desktop/Makefile +++ b/desktop/Makefile @@ -44,7 +44,8 @@ APPS := core \ libs/liboozie \ libs/libsaml \ libs/librdbms \ - libs/libopenid + libs/libopenid \ + libs/liboauth .PHONY: default default:: hue syncdb diff --git a/desktop/conf.dist/hue.ini b/desktop/conf.dist/hue.ini index ccf5eae..bcfb4ae 100644 --- a/desktop/conf.dist/hue.ini +++ b/desktop/conf.dist/hue.ini @@ -100,8 +100,11 @@ # - desktop.auth.backend.SpnegoDjangoBackend # - desktop.auth.backend.RemoteUserDjangoBackend # - desktop.auth.backend.OAuthBackend + # (Core oauth authentication, only support twitter) # - libsaml.backend.SAML2Backend # - libopenid.backend.OpenIDBackend + # - liboauth.backend.OAuthBackend + # (New oauth, support Twitter, Facebook, Google+ and Linkedin ## backend=desktop.auth.backend.AllowFirstUserDjangoBackend ## pam_service=login @@ -245,7 +248,7 @@ ## kinit_path=/path/to/kinit - # Configuration options for using OAuthBackend login + # Configuration options for using OAuthBackend (core) login # ------------------------------------------------------------------------ [[oauth]] # The Consumer key of the application @@ -332,6 +335,59 @@ ########################################################################### +# Settings to configure OAuth (New) +########################################################################### + +[liboauth] + # NOTE: + # To work, each of the active (i.e. uncommented) service must have + # applications created on the social network. + # Then the "consumer key" and "consumer secret" must be provided here. + # + # The addresses where to do so are: + # Twitter: https://dev.twitter.com/apps + # Google+ : https://cloud.google.com/ + # Facebook: https://developers.facebook.com/apps + # Linkedin: https://www.linkedin.com/secure/developer + # + # Additionnaly, the following must be set in the application settings: + # Twitter: Callback URL (aka Redirect URL) must be set to http://YOUR_HUE_IP_OR_DOMAIN_NAME/oauth/social_login/oauth_authenticated + # Google+ : CONSENT SCREEN must have email address + # Facebook: Sandbox Mode must be DISABLED + # Linkedin: "In OAuth User Agreement", r_emailaddress is REQUIRED + + # The Consumer key of the application + ## consumer_key_twitter= + ## consumer_key_google= + ## consumer_key_facebook= + ## consumer_key_linkedin= + + # The Consumer secret of the application + ## consumer_secret_twitter= + ## consumer_secret_google= + ## consumer_secret_facebook= + ## consumer_secret_linkedin= + + # The Request token URL + ## request_token_url_twitter=https://api.twitter.com/oauth/request_token + ## request_token_url_google=https://accounts.google.com/o/oauth2/auth + ## request_token_url_linkedin=https://www.linkedin.com/uas/oauth2/authorization + ## request_token_url_facebook=https://graph.facebook.com/oauth/authorize + + # The Access token URL + ## access_token_url_twitter=https://api.twitter.com/oauth/access_token?oauth_verifier= + ## access_token_url_google=https://accounts.google.com/o/oauth2/token + ## access_token_url_facebook=https://graph.facebook.com/oauth/access_token + ## access_token_url_linkedin=https://api.linkedin.com/uas/oauth2/accessToken + + # The Authenticate URL + ## authenticate_url_twitter=https://api.twitter.com/oauth/authenticate + ## authenticate_url_google=https://www.googleapis.com/oauth2/v1/userinfo?access_token= + ## authenticate_url_facebook=https://graph.facebook.com/me?access_token= + ## authenticate_url_linkedin=https://api.linkedin.com/v1/people/~:(email-address)?format=json&oauth2_access_token= + + +########################################################################### # Settings for the RDBMS application ########################################################################### diff --git a/desktop/conf/pseudo-distributed.ini.tmpl b/desktop/conf/pseudo-distributed.ini.tmpl index 6c0dbec..03b0363 100644 --- a/desktop/conf/pseudo-distributed.ini.tmpl +++ b/desktop/conf/pseudo-distributed.ini.tmpl @@ -109,7 +109,11 @@ # - desktop.auth.backend.SpnegoDjangoBackend # - desktop.auth.backend.RemoteUserDjangoBackend # - desktop.auth.backend.OAuthBackend + # (Core oauth authentication, only support twitter) # - libsaml.backend.SAML2Backend + # - libopenid.backend.OpenIDBackend + # - liboauth.backend.OAuthBackend + # (New oauth, support Twitter, Facebook, Google+ and Linkedin ## backend=desktop.auth.backend.AllowFirstUserDjangoBackend ## pam_service=login @@ -250,7 +254,7 @@ ## kinit_path=/path/to/kinit - # Configuration options for using OAuthBackend login + # Configuration options for using OAuthBackend (Core) login # ------------------------------------------------------------------------ [[oauth]] # The Consumer key of the application @@ -337,6 +341,59 @@ ########################################################################### +# Settings to configure OAuth (New) +########################################################################### + +[liboauth] + # NOTE: + # To work, each of the active (i.e. uncommented) service must have + # applications created on the social network. + # Then the "consumer key" and "consumer secret" must be provided here. + # + # The addresses where to do so are: + # Twitter: https://dev.twitter.com/apps + # Google+ : https://cloud.google.com/ + # Facebook: https://developers.facebook.com/apps + # Linkedin: https://www.linkedin.com/secure/developer + # + # Additionnaly, the following must be set in the application settings: + # Twitter: Callback URL (aka Redirect URL) must be set to http://YOUR_HUE_IP_OR_DOMAIN_NAME/oauth/social_login/oauth_authenticated + # Google+ : CONSENT SCREEN must have email address + # Facebook: Sandbox Mode must be DISABLED + # Linkedin: "In OAuth User Agreement", r_emailaddress is REQUIRED + + # The Consumer key of the application + ## consumer_key_twitter= + ## consumer_key_google= + ## consumer_key_facebook= + ## consumer_key_linkedin= + + # The Consumer secret of the application + ## consumer_secret_twitter= + ## consumer_secret_google= + ## consumer_secret_facebook= + ## consumer_secret_linkedin= + + # The Request token URL + ## request_token_url_twitter=https://api.twitter.com/oauth/request_token + ## request_token_url_google=https://accounts.google.com/o/oauth2/auth + ## request_token_url_linkedin=https://www.linkedin.com/uas/oauth2/authorization + ## request_token_url_facebook=https://graph.facebook.com/oauth/authorize + + # The Access token URL + ## access_token_url_twitter=https://api.twitter.com/oauth/access_token?oauth_verifier= + ## access_token_url_google=https://accounts.google.com/o/oauth2/token + ## access_token_url_facebook=https://graph.facebook.com/oauth/access_token + ## access_token_url_linkedin=https://api.linkedin.com/uas/oauth2/accessToken + + # The Authenticate URL + ## authenticate_url_twitter=https://api.twitter.com/oauth/authenticate + ## authenticate_url_google=https://www.googleapis.com/oauth2/v1/userinfo?access_token= + ## authenticate_url_facebook=https://graph.facebook.com/me?access_token= + ## authenticate_url_linkedin=https://api.linkedin.com/v1/people/~:(email-address)?format=json&oauth2_access_token= + + +########################################################################### # Settings for the RDBMS application ########################################################################### diff --git a/desktop/core/src/desktop/settings.py b/desktop/core/src/desktop/settings.py index e12fee5..5734389 100644 --- a/desktop/core/src/desktop/settings.py +++ b/desktop/core/src/desktop/settings.py @@ -324,6 +324,13 @@ if OPENID_AUTHENTICATION: LOGIN_URL = '/openid/login' SESSION_EXPIRE_AT_BROWSER_CLOSE = True +# OAuth +OAUTH_AUTHENTICATION='liboauth.backend.OAuthBackend' in AUTHENTICATION_BACKENDS +if OAUTH_AUTHENTICATION: + INSTALLED_APPS.append('liboauth') + LOGIN_URL = '/oauth/accounts/login' + SESSION_EXPIRE_AT_BROWSER_CLOSE = True + # URL Redirection white list. if desktop.conf.REDIRECT_WHITELIST.get(): MIDDLEWARE_CLASSES.append('desktop.middleware.EnsureSafeRedirectURLMiddleware') diff --git a/desktop/core/src/desktop/urls.py b/desktop/core/src/desktop/urls.py index da794be..a4a6823 100644 --- a/desktop/core/src/desktop/urls.py +++ b/desktop/core/src/desktop/urls.py @@ -101,6 +101,11 @@ if settings.SAML_AUTHENTICATION: if settings.OPENID_AUTHENTICATION: static_patterns.append((r'^openid/', include('libopenid.urls'))) +if settings.OAUTH_AUTHENTICATION: + static_patterns.append((r'^oauth/', include('liboauth.urls'))) + static_patterns.append(static_pattern("liboauth_static", + os.path.join(os.path.dirname(__file__), "..", '..', '..', "libs/liboauth/src/liboauth/static/"))) + # Root each app at /appname if they have a "urls" module for app in appmanager.DESKTOP_APPS: if app.urls: diff --git a/desktop/libs/liboauth/Makefile b/desktop/libs/liboauth/Makefile new file mode 100644 index 0000000..1bda9cf --- /dev/null +++ b/desktop/libs/liboauth/Makefile @@ -0,0 +1,36 @@ +# +# Licensed to Cloudera, Inc. under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. Cloudera, Inc. licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + +ifeq ($(ROOT),) + $(error "Error: Expect the environment variable $$ROOT to point to the Desktop installation") +endif + +include $(ROOT)/Makefile.sdk + +default:: + @echo ' env-install : Install into virtual-env' + +# +# env-install +# Install app into the virtual environment. +# +.PHONY: env-install +env-install: compile ext-env-install + @echo '--- Installing $(APP_NAME) into virtual-env' + @$(ENV_PYTHON) setup.py develop -N -q diff --git a/desktop/libs/liboauth/babel.cfg b/desktop/libs/liboauth/babel.cfg new file mode 100644 index 0000000..567b623 --- /dev/null +++ b/desktop/libs/liboauth/babel.cfg @@ -0,0 +1,2 @@ +[python: src/liboauth/**.py] +[mako: src/liboauth/templates/**.mako] diff --git a/desktop/libs/liboauth/setup.py b/desktop/libs/liboauth/setup.py new file mode 100644 index 0000000..84ac1ed --- /dev/null +++ b/desktop/libs/liboauth/setup.py @@ -0,0 +1,30 @@ +# Licensed to Cloudera, Inc. under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. Cloudera, Inc. licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from setuptools import setup, find_packages + +setup( + name = "liboauth", + version = "1.0", + url = 'http://github.com/cloudera/hue', + description = "OAuth Libraries", + packages = find_packages('src'), + package_dir = {'': 'src' }, + install_requires = ['setuptools', 'desktop'], + # Even libraries need to be registered as desktop_apps, + # if they have configuration, like this one. + entry_points = { 'desktop.sdk.lib': 'liboauth=liboauth' }, +) diff --git a/desktop/libs/liboauth/src/liboauth/__init__.py b/desktop/libs/liboauth/src/liboauth/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/desktop/libs/liboauth/src/liboauth/backend.py b/desktop/libs/liboauth/src/liboauth/backend.py new file mode 100644 index 0000000..5600c81 --- /dev/null +++ b/desktop/libs/liboauth/src/liboauth/backend.py @@ -0,0 +1,269 @@ +#!/usr/bin/env python +# Licensed to Cloudera, Inc. under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. Cloudera, Inc. licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" +See desktop/auth/backend.py +""" +import logging +import sys +from django.contrib.auth import logout as auth_logout +from django.contrib.auth.models import User +from desktop.auth.backend import DesktopBackendBase +from desktop.auth.backend import rewrite_user +from django.http import HttpResponseRedirect +from useradmin.models import get_profile, get_default_user_group, UserProfile +from django.utils.translation import ugettext as _ +from hadoop.fs.exceptions import WebHdfsException + +import liboauth.conf +try: + import oauth2 as oauth +except: + pass +import httplib2 +import json +import urllib +import cgi + + +LOG = logging.getLogger(__name__) + +class OAuthBackend(DesktopBackendBase): + + def authenticate(self, access_token): + username = access_token['screen_name'] + password = access_token['oauth_token_secret'] + + try: + user = User.objects.get(username=username) + except User.DoesNotExist: + + if not UserProfile.objects.filter(creation_method=str(UserProfile.CreationMethod.EXTERNAL)).exists(): + is_super=True + else: + is_super=False + + # Could save oauth_token detail in the user profile here + user = find_or_create_user(username, password) + + profile = get_profile(user) + profile.creation_method = UserProfile.CreationMethod.EXTERNAL + profile.save() + + user.is_superuser = is_super + user.save() + + default_group = get_default_user_group() + if default_group is not None: + user.groups.add(default_group) + + return user + + + @classmethod + def manages_passwords_externally(cls): + return True + + @classmethod + def is_first_login_ever(cls): + """ Return true if no external user has ever logged in to Desktop yet. """ + return not UserProfile.objects.filter(creation_method=str(UserProfile.CreationMethod.EXTERNAL)).exists() + + + @classmethod + def handleAuthenticationRequest(self, request): + + if 'oauth_verifier' in request.GET: + social = 'twitter' + consumer_key=liboauth.conf.CONSUMER_KEY_TWITTER.get() + consumer_secret=liboauth.conf.CONSUMER_SECRET_TWITTER.get() + access_token_uri=liboauth.conf.ACCESS_TOKEN_URL_TWITTER.get() + + consumer = oauth.Consumer(consumer_key, consumer_secret) + token = oauth.Token(request.session['request_token']['oauth_token'], request.session['request_token']['oauth_token_secret']) + client = oauth.Client(consumer, token) + oauth_verifier=request.GET['oauth_verifier'] + resp, content = client.request(access_token_uri + oauth_verifier, "GET") + if resp['status'] != '200': + raise Exception(_("Invalid response from OAuth provider: %s") % resp) + access_token = dict(cgi.parse_qsl(content)) + access_token['screen_name'] = ''.join([x for x in access_token['screen_name'] if x.isalnum()]) + + else: + parser = httplib2.Http() + login_failed_url = '/' + if 'error' in request.GET or 'code' not in request.GET: + return "" + + redirect_uri = 'http://' + request.get_host() + '/oauth/social_login/oauth_authenticated' + code = request.GET['code'] + grant_type = 'authorization_code' + + if request.GET['state'] == 'google': + social = 'google' + consumer_key=liboauth.conf.CONSUMER_KEY_GOOGLE.get() + consumer_secret=liboauth.conf.CONSUMER_SECRET_GOOGLE.get() + access_token_uri=liboauth.conf.ACCESS_TOKEN_URL_GOOGLE.get() + authentication_token_uri=liboauth.conf.AUTHORIZE_URL_GOOGLE.get() + + elif request.GET['state'] == 'facebook': + social = 'facebook' + consumer_key=liboauth.conf.CONSUMER_KEY_FACEBOOK.get() + consumer_secret=liboauth.conf.CONSUMER_SECRET_FACEBOOK.get() + access_token_uri=liboauth.conf.ACCESS_TOKEN_URL_FACEBOOK.get() + authentication_token_uri=liboauth.conf.AUTHORIZE_URL_FACEBOOK.get() + + elif request.GET['state'] == 'linkedin': + social = 'linkedin' + consumer_key=liboauth.conf.CONSUMER_KEY_LINKEDIN.get() + consumer_secret=liboauth.conf.CONSUMER_SECRET_LINKEDIN.get() + access_token_uri=liboauth.conf.ACCESS_TOKEN_URL_LINKEDIN.get() + authentication_token_uri=liboauth.conf.AUTHORIZE_URL_LINKEDIN.get() + + params = urllib.urlencode({ + 'code':code, + 'redirect_uri':redirect_uri, + 'client_id': consumer_key, + 'client_secret': consumer_secret, + 'grant_type':grant_type + }) + headers={'content-type':'application/x-www-form-urlencoded'} + resp, cont = parser.request(access_token_uri, method = 'POST', body = params, headers = headers) + if resp['status'] != '200': + raise Exception(_("Invalid response from OAuth provider: %s") % resp) + + #google + if social == 'google': + access_tok = (json.loads(cont))['access_token'] + auth_token_uri = authentication_token_uri + access_tok + resp, content = parser.request(auth_token_uri, "GET") + if resp['status'] != '200': + raise Exception(_("Invalid response from OAuth provider: %s") % resp) + username=(json.loads(content))["email"] + access_token = dict(screen_name=''.join([x for x in username if x.isalnum()]), oauth_token_secret=access_tok) + #facebook + elif social == 'facebook': + access_tok = (dict(cgi.parse_qsl(cont)))['access_token'] + auth_token_uri = authentication_token_uri + access_tok + resp, content = parser.request(auth_token_uri, "GET") + if resp['status'] != '200': + raise Exception(_("Invalid response from OAuth provider: %s") % resp) + username = (json.loads(content))["email"] + access_token = dict(screen_name=''.join([x for x in username if x.isalnum()]), oauth_token_secret=access_tok) + #linkedin + elif social == 'linkedin': + access_tok = (json.loads(cont))['access_token'] + auth_token_uri = authentication_token_uri + access_tok + resp, content = parser.request(auth_token_uri, "GET") + if resp['status'] != '200': + raise Exception(_("Invalid response from OAuth provider: %s") % resp) + username = (json.loads(content))['emailAddress'] + access_token = dict(screen_name=''.join([x for x in username if x.isalnum()]), oauth_token_secret=access_tok) + + + return access_token + + @classmethod + def handleLoginRequest(self, request): + + redirect_uri = 'http://' + request.get_host() + '/oauth/social_login/oauth_authenticated' + response_type = "code" + + social = request.GET['social'] + + if social == 'google': + consumer_key=liboauth.conf.CONSUMER_KEY_GOOGLE.get() + token_request_uri = liboauth.conf.REQUEST_TOKEN_URL_GOOGLE.get() + scope = "https://www.googleapis.com/auth/userinfo.email" + access_type="offline" + approval_prompt="force" + state="google" + + url = "{token_request_uri}?response_type={response_type}&client_id={client_id}&redirect_uri={redirect_uri}&scope={scope}&state={state}&access_type={access_type}&approval_prompt={approval_prompt}".format( + token_request_uri = token_request_uri, + response_type = response_type, + client_id = consumer_key, + redirect_uri = redirect_uri, + scope = scope, + state = state, + access_type = access_type, + approval_prompt = approval_prompt) + + #facebook + elif social == 'facebook': + consumer_key=liboauth.conf.CONSUMER_KEY_FACEBOOK.get() + token_request_uri = liboauth.conf.REQUEST_TOKEN_URL_FACEBOOK.get() + scope = "email" + grant_type = "client_credentials" + state = "facebook" + + url = "{token_request_uri}?client_id={client_id}&redirect_uri={redirect_uri}&grant_type={grant_type}&scope={scope}&state={state}".format( + token_request_uri=token_request_uri, + client_id=consumer_key, + redirect_uri=redirect_uri, + grant_type=grant_type, + scope=scope, + state=state) + + #linkedin + elif social == 'linkedin': + consumer_key=liboauth.conf.CONSUMER_KEY_LINKEDIN.get() + token_request_uri = liboauth.conf.REQUEST_TOKEN_URL_LINKEDIN.get() + scope= "r_emailaddress" + state= "linkedin" + + url = "{token_request_uri}?response_type={response_type}&client_id={client_id}&scope={scope}&state={state}&redirect_uri={redirect_uri}".format( + token_request_uri=token_request_uri, + response_type=response_type, + client_id=consumer_key, + scope=scope, + state=state, + redirect_uri=redirect_uri) + #twitter + else: + consumer_key=liboauth.conf.CONSUMER_KEY_TWITTER.get() + consumer_secret=liboauth.conf.CONSUMER_SECRET_TWITTER.get() + token_request_uri = liboauth.conf.REQUEST_TOKEN_URL_TWITTER.get() + token_authentication_uri = liboauth.conf.AUTHORIZE_URL_TWITTER.get() + + consumer = oauth.Consumer(consumer_key, consumer_secret) + client = oauth.Client(consumer) + resp, content = client.request(token_request_uri, "POST", body=urllib.urlencode({ + 'oauth_callback': redirect_uri})) + if resp['status'] != '200': + raise Exception(_("Invalid response from OAuth provider: %s") % resp) + request.session['request_token'] = dict(cgi.parse_qsl(content)) + url = "{token_authentication_uri}?oauth_token={oauth_token}".format( + token_authentication_uri=token_authentication_uri, + oauth_token=request.session['request_token']['oauth_token'] + ) + return url + + +def find_or_create_user(username, password=None): + try: + user = User.objects.get(username=username) + LOG.debug("Found user %s in the db" % username) + except User.DoesNotExist: + LOG.info("Materializing user %s in the database" % username) + user = User(username=username) + if password is None: + user.set_unusable_password() + else: + user.set_password(password) + user.is_superuser = True + user.save() + return user diff --git a/desktop/libs/liboauth/src/liboauth/conf.py b/desktop/libs/liboauth/src/liboauth/conf.py new file mode 100644 index 0000000..bed23cb --- /dev/null +++ b/desktop/libs/liboauth/src/liboauth/conf.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python +# Licensed to Cloudera, Inc. under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. Cloudera, Inc. licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +from django.utils.translation import ugettext_lazy as _t, ugettext as _ + +from desktop.lib.conf import Config, coerce_bool + +CONSUMER_KEY_TWITTER = Config( + key="consumer_key_twitter", + help=_t("The Consumer key of the twitter application."), + type=str, + default="" + ) +CONSUMER_KEY_GOOGLE = Config( + key="consumer_key_google", + help=_t("The Consumer key of the google application."), + type=str, + default="" + ) +CONSUMER_KEY_FACEBOOK = Config( + key="consumer_key_facebook", + help=_t("The Consumer key of the facebook application."), + type=str, + default="" + ) +CONSUMER_KEY_LINKEDIN = Config( + key="consumer_key_linkedin", + help=_t("The Consumer key of the linkedin application."), + type=str, + default="" + ) + +CONSUMER_SECRET_TWITTER = Config( + key="consumer_secret_twitter", + help=_t("The Consumer secret of the twitter application."), + type=str, + default="" + ) +CONSUMER_SECRET_GOOGLE = Config( + key="consumer_secret_google", + help=_t("The Consumer secret of the google application."), + type=str, + default="" + ) +CONSUMER_SECRET_FACEBOOK = Config( + key="consumer_secret_facebook", + help=_t("The Consumer secret of the facebook application."), + type=str, + default="" + ) +CONSUMER_SECRET_LINKEDIN = Config( + key="consumer_secret_linkedin", + help=_t("The Consumer secret of the linkedin application."), + type=str, + default="" + ) + + +REQUEST_TOKEN_URL_TWITTER = Config( + key="request_token_url_twitter", + help=_t("The Twitter Request token URL."), + type=str, + default="https://api.twitter.com/oauth/request_token" + ) +REQUEST_TOKEN_URL_GOOGLE = Config( + key="request_token_url_google", + help=_t("The Google Request token URL."), + type=str, + default="https://accounts.google.com/o/oauth2/auth" + ) +REQUEST_TOKEN_URL_FACEBOOK = Config( + key="request_token_url_facebook", + help=_t("The Facebook Request token URL."), + type=str, + default="https://graph.facebook.com/oauth/authorize" + ) +REQUEST_TOKEN_URL_LINKEDIN = Config( + key="request_token_url_linkedin", + help=_t("The Linkedin Request token URL."), + type=str, + default="https://www.linkedin.com/uas/oauth2/authorization" + ) + +ACCESS_TOKEN_URL_TWITTER = Config( + key="access_token_url_twitter", + help=_t("The Twitter Access token URL."), + type=str, + default="https://api.twitter.com/oauth/access_token" + ) +ACCESS_TOKEN_URL_GOOGLE = Config( + key="access_token_url_google", + help=_t("The Google Access token URL."), + type=str, + default="https://accounts.google.com/o/oauth2/token" + ) +ACCESS_TOKEN_URL_FACEBOOK = Config( + key="access_token_url_facebook", + help=_t("The Facebook Access token URL."), + type=str, + default="https://graph.facebook.com/oauth/access_token" + ) +ACCESS_TOKEN_URL_LINKEDIN = Config( + key="access_token_url_linkedin", + help=_t("The Linkedin Access token URL."), + type=str, + default="https://api.linkedin.com/uas/oauth2/accessToken" + ) + + +AUTHORIZE_URL_TWITTER = Config( + key="authenticate_url_twitter", + help=_t("The Twitter Authorize URL."), + type=str, + default="https://api.twitter.com/oauth/authorize" + ) +AUTHORIZE_URL_GOOGLE = Config( + key="authenticate_url_google", + help=_t("The Google Authorize URL."), + type=str, + default="https://www.googleapis.com/oauth2/v1/userinfo" + ) +AUTHORIZE_URL_FACEBOOK = Config( + key="authenticate_url_facebook", + help=_t("The Facebook Authorize URL."), + type=str, + default="https://graph.facebook.com/me" + ) +AUTHORIZE_URL_LINKEDIN = Config( + key="authenticate_url_linkedin", + help=_t("The Linkedin Authorize URL."), + type=str, + default="https://api.linkedin.com/v1/people/~" + ) diff --git a/desktop/libs/liboauth/src/liboauth/locale/en/LC_MESSAGES/django.po b/desktop/libs/liboauth/src/liboauth/locale/en/LC_MESSAGES/django.po new file mode 100644 index 0000000..1bf7690 --- /dev/null +++ b/desktop/libs/liboauth/src/liboauth/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,20 @@ +# English translations for PROJECT. +# Copyright (C) 2014 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2014. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2014-01-10 21:27+0000\n" +"PO-Revision-Date: 2014-01-10 22:19+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: en \n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 0.9.6\n" + diff --git a/desktop/libs/liboauth/src/liboauth/locale/en_US.pot b/desktop/libs/liboauth/src/liboauth/locale/en_US.pot new file mode 100644 index 0000000..4ff65fb --- /dev/null +++ b/desktop/libs/liboauth/src/liboauth/locale/en_US.pot @@ -0,0 +1,19 @@ +# Translations template for PROJECT. +# Copyright (C) 2014 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2014. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2014-01-10 21:27+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 0.9.4\n" + diff --git a/desktop/libs/liboauth/src/liboauth/static/art/icon-fb.png b/desktop/libs/liboauth/src/liboauth/static/art/icon-fb.png new file mode 100644 index 0000000000000000000000000000000000000000..87ecab76469bb86686d2a6911fcef420d6378a56 GIT binary patch literal 1221 zcmeAS@N?(olHy`uVBq!ia0vp^0zj<5!3HFyJAa%3Qj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS=07?_nZLn2Bde0{8v^Kf6`()~Xj@TAnpKdC8`Lf!&sHg;q@=(~U%$M( zT(8_%FTW^V-_X+15@d#vkuFe$ZgFK^Nn(X=Ua>OF1ees}+T7#d8#0MoBXEYLU9GXQxBrqI_HztY@Xxa#7Ppj3o=u^L<)Qdy9y zACy|0Us{w5jJPyqkW~d%&PAz-CHX}m`T04pPz=b(FUc>?$S+WE4mMNJ2+zz*$uBR~ z1grP;werj>E=kNwPW5!LRRWrzmzkMj<>qK=Zth}YVP@fMW@zYYY~f;RW?^aI;%sPQ zZs}xd4Abk9pIn-onpXnTn}X15iBm5qDdZLaZFWg5$}CGwaVyHtRRDY0DigO`%y60q z)tiFbE#^4&>H{644~kf%h=vIPQxAv(b*TCG{=WVG|H+KHbA_`VvNmR#u|L}WpR?h@4a9-d&(I9omVI89#j|!7m%DMOV>!(CUMsCouDgP&Qcy)OGgFpH9bqP`jKKz$g zH#?hsEk8A5p3�`~Uw}XWkiKxQjvDqV}B8sn@DKld z`{riGNmUb1HO1T4*Bujklxn*6f2m9@&jwLD5%nd3%x=6ArVQSDH{?D3wo3LlpRZH+ immg2P=ddxbNH9!w)1Fk@bk_+~uz0%qxvXr5;N*?{uSPF#$=oBKezmP^@zwYsBy+n+W^0qb6%C?Lin7T&N z+qw4B^3%CfzjB?v{(Bv^Iw|9y9P7guT23X26M{N3IXOpkr>%3yjfXb=7}9yq=SXV? z+bf&J=C+;e%^ynsRx4HiwW^jz*-e^X@svhKYE|y@qP!oCd1u0l`Fe6kKqJbS(vftAlQV?R9EKiQf3s;@7*i+>Tzx)o8) zic;1}yK}r_x5_@-z+Agkf?Gi?OMdYF#;X^KYRaoCQX@Y05XcUNQ_XO`MP0O!a<^*~Hy9pIBM0 zyr3MAWhW*I*s*U1(phEyiQm<9?9Rl_psn=T-zvN7+c&nMJJQlmRea--l~R0>FiEaQdIN)aFCW~pn2Eg(TH+W;AZ5> zcWIxfPSm~a!XiJ2c9FTR?=(MNZ!LfGj?N>&_dJvO?sm5sKR=P%^Z3PJB;sHYt=4MV z7MwpHXaBSaeZ4*};CuDQ8zN2FBOR70vF-`(3H$5EZKOZzd|$G7AgwA+{i&zlN$t?B zq0^Ys?2LiBcY+z$NSeas=&s$SXOQ?rvTpC7_;-m>DT8@)X4vj0=-XP&eZ+x|hBD_6 z#m7J?*y=BZ-<>W~1lAUN#R%c4byWe)Lk7MnwG}mUZ~#6t3WWT|XD#*&DVsU)yGH z*)7Vta${_q5c{sQ@p3aM!=;Suy#{_o-5obzn>v5aj}CE8GcCJ5wCC|$7u#!Vh}w!8 z)!dk&q8B}Ta|~}}YZc~Y%{-`L0sk0ZL~l`%dN>EVEVXQ8qR^`n_SYUTH#!*EL!;N) z1es#*7G{|bQiXuZz)tj7hMSbVE1}}jt*nzraZTyUx`|Nz(kv?#v%w5uC22PN?pg zA4yr*PVlPe=R(S-i;2_zRinB4AF9_Pj7Wd_!B|+s;aAvEBI<&d9rF9YTHmk~*Zg`ePc>SQp zCt|L#D@CR6z~wX2@zvJsXAUCF;gY1BYtB;tvwqV*|1hTGz1iP%SUMJ^^ytn|%@T%0 zz}DGm236G@3Ahx_88^RQGs4@8LIm2(&N$s204Z`?a|urh&3PdU0`!S<9QS zIZ3dVR8Yt=8LGD%v5~lJb9QI9hM@ITXWP7U?<9@wu3+W+2Vl(1YR}{x>wcK1a&v=I zE;BM-4Gr`_^Czd)Z_>5v(oia%D8_AYn>JLWe5Etm7V+te{h&4 literal 0 HcmV?d00001 diff --git a/desktop/libs/liboauth/src/liboauth/static/art/icon-linkedin.png b/desktop/libs/liboauth/src/liboauth/static/art/icon-linkedin.png new file mode 100644 index 0000000000000000000000000000000000000000..6a09179cbd53b652836fd7c45835b92d1f45ced0 GIT binary patch literal 1544 zcmeAS@N?(olHy`uVBq!ia0vp^N8U}fi7AzZCsS=07?_nZLn2Bde0{8v^Kf6`()~Xj@TAnpKdC8`Lf!&sHg;q@=(~U%$M( zT(8_%FTW^V-_X+15@d#vkuFe$ZgFK^Nn(X=Ua>OF1ees}+T7#d8#0MoBXEYLU9GXQxBrqI_HztY@Xxa#7Ppj3o=u^L<)Qdy9y zACy|0Us{w5jJPyqkW~d%&PAz-CHX}m`T04pPz=b(FUc>?$S+WE4mMNJ2+zz*$uBR~ z1grP;werj>E=kNwPW5!LRRWrzmzkMjWo&3*Zs=@gX=dSUX=vzbY+>qX=xAW*?CfUf zWNhwY2Gi@3pIn-onpXnTn}X2mh*K{pDdZLaZFWg5$}CGwaVyHtRRDY0DigO`%yF6r z)tiFbEfzTS>H{644~kf%h=vIPQxAvQ1J z9?VW=hN)6KtqokyLM4vqO{`vE@`0Liy<`Vbz{r@1S z5n7u2e_CcqF$WKW>=EuITN;0u3&b;8JyPFWq_1qCHlxu*pYP}To}Qll6BkY7pS5m7 z<9mm#_7kr(oe5=33RL*Vc!a<4)B2A~1({=>o;WDHoV#)1k^Uv$81=S>=ihzFwn~)M zD73M{PN3c;{PW-A{k!Y`{n2DMvh*nO$jjx{*vKaEctW4%=KuP)H9pEu&3hh zGg|}qs72}Vs~Ci9W!pUJ*K;ULo;x9`P%x2^+j+0D=F+YELdrWf_p-V@I{sQBP;i+8 z|MaZ~1j5yiE6T5&8Ehk)8yPC{M6BtC&XQ^MEh2Mv*Yqa--#D44{{P?P4Ti>P8;r~j z%uSV)l*~EXbN0Q>hm8q~mhq?SM4l7~4>)L$|8$orcX)n>m+o5L$jznCIcutVzB(Kg zb7tV)DpUCS9&_8u&(oWV!Zp;7OBN1I zH)5DwF5Y;?Zp(xJ>?KEnVt)Pjc_4MA)>WBLZ*P|iY~_`Zx^d~E>>R#_PZ(@b91-)pO2U8|9BHQIsE!5wl^ov9$CtuaDc%m_SCXNpHKY(mCc^6 KelF{r5}E+caz-Wq literal 0 HcmV?d00001 diff --git a/desktop/libs/liboauth/src/liboauth/static/art/icon-twitter.png b/desktop/libs/liboauth/src/liboauth/static/art/icon-twitter.png new file mode 100644 index 0000000000000000000000000000000000000000..3391eff7a9ff50ecca141e4a0d3a53c9423a19df GIT binary patch literal 1407 zcmeAS@N?(olHy`uVBq!ia0vp^5DSr z1<%~X^wgl##FWaylc_cg49rTIArU1JzCKpT`MG+DAT@dwxdlMo3=B5*6$OdO*{LN8 zNvY|XdA3ULckfqH$V{%1*XSQL?vFu&J;D8jzb> zlBiITo0C^;Rbi_HHrEQs1_|pcDS(xfWZNo192Makpx~Tel&WB=XRMoSU}&gdW~OIo zVrph)sH0$HU}&Uo07PcGh9*{~W>!Y#3Q(W~w5=#5%__*n4QdyVXRDM^Qc_^0uU}qX zu2*iXmtT~wZ)j<02{OaTNEfI=x41H|B(Xv_uUHvof=g;~a#3bMNoIbY0?5R~r2Ntn zTP2`NAzsKWfE$}v3=Jk=fazBx7U&!58GyV5Q|Rl9UukYGTy=3tP%6T`SPd=?sVqp< z4@xc0FD*(2MqHXQ$f^P>=c3falKi5O{QMkPCgz0t3PcF?(%`1WFO+n~&!KoLN6mkoIHoK%2WtOF;xE1B+DuBIgm5JLejyTPO z>P^Az7AKr~^?{Dj2SqGWM8kxDsRzV_CtDx~p72xifT_I*n5+$d?w!EE!1&qI#WAGf zR#E~()Bpef)tNrlD*XHZ`1yJB{`t1+(-#OZ^fD#Scqox@^Ovss7Ma=^D-sXd=7`n& z`t)@FME3y8rD6>+D>{4`_07$jH!N_lTI$$p&LJT=(CJ&AmsBl+OHQJ7O&%DQT{lZX(f~_29!v;{}geCHJmapyi>pF0MB&BtX=|yQ7t% zR?&5{N8SIA!W}^iI$8VY*`-@l{rVHH@Y$?rqnBvGr$0yk=LMep-+1tHqYS&wj~I~| zlYYOyI(z$dj-7v=ufP9)|NkE!xlY9J9r=7gn{CbkU9G3Wrdl$0ZqDhP_-PSS#%cSQ zNt=Qu%@Mi%;rI9V?mL=ZyqNjFBzu#Yf`s2~VoyFqujI#~1om~&)?tQ**8r3*X;c3{`&a+^Zx$$xjNpXpLNCmUYARVOK4#i z+0kvv6|oi{_bBIpQ78vs!;Is*jm>sn^Y`x-}APyI`BQ-X#D(p@L{Ii4{rRI z5Ib;SQt525+CN`r<{ajiv1ZlkfA?q$151!s)}CkUB7T25_;|UBB%jZv|7-s!JBqm+ zo~*epg)=v@`lP3~nnzb>R6${p7gIN%+8fUw@`pE1UoVk&x4MA;#M=Ga>Q4*Jc+JSf Z!|-qt^U*>Z9&=EU=;`X`vd$@?2>=Am5upG8 literal 0 HcmV?d00001 diff --git a/desktop/libs/liboauth/src/liboauth/templates/oauth-login.mako b/desktop/libs/liboauth/src/liboauth/templates/oauth-login.mako new file mode 100644 index 0000000..d628dbd --- /dev/null +++ b/desktop/libs/liboauth/src/liboauth/templates/oauth-login.mako @@ -0,0 +1,252 @@ +## Licensed to Cloudera, Inc. under one +## or more contributor license agreements. See the NOTICE file +## distributed with this work for additional information +## regarding copyright ownership. Cloudera, Inc. licenses this file +## to you under the Apache License, Version 2.0 (the +## "License"); you may not use this file except in compliance +## with the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +<%! +from desktop import conf +from django.utils.translation import ugettext as _ +%> + + + + + %if first_login_ever: + ${_('Hue - Sign up')} + %else: + ${_('Hue - Sign in')} + %endif + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + + + diff --git a/desktop/libs/liboauth/src/liboauth/urls.py b/desktop/libs/liboauth/src/liboauth/urls.py new file mode 100644 index 0000000..6ed45c5 --- /dev/null +++ b/desktop/libs/liboauth/src/liboauth/urls.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python +# Licensed to Cloudera, Inc. under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. Cloudera, Inc. licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from django.conf.urls.defaults import patterns, url + +urlpatterns = patterns( + 'liboauth.views', + url(r'^accounts/login/$', 'show_login_page', name='show_oauth_login'), + url(r'^social_login/oauth/?$', 'oauth_login', name='oauth_login'), + url(r'^social_login/oauth_authenticated/?$', 'oauth_authenticated', name='oauth_authenticated'), +) + + diff --git a/desktop/libs/liboauth/src/liboauth/views.py b/desktop/libs/liboauth/src/liboauth/views.py new file mode 100644 index 0000000..4a681d6 --- /dev/null +++ b/desktop/libs/liboauth/src/liboauth/views.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +# Licensed to Cloudera, Inc. under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. Cloudera, Inc. licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +try: + import oauth2 as oauth +except: + pass + +import logging +import urllib +import httplib2 + +import django.contrib.auth.views +from django.core import urlresolvers +from django.core.exceptions import SuspiciousOperation +from django.contrib.auth import login, get_backends, authenticate +from django.contrib.auth.models import User +from django.contrib.sessions.models import Session +from django.http import HttpResponseRedirect +from django.utils.translation import ugettext as _ +from hadoop.fs.exceptions import WebHdfsException +from useradmin.views import ensure_home_directory + +from desktop.auth.backend import AllowFirstUserDjangoBackend +from desktop.auth.forms import UserCreationForm, AuthenticationForm +from desktop.lib.django_util import render +from desktop.lib.django_util import login_notrequired +from desktop.log.access import access_warn, last_access_map + +import liboauth.conf +from liboauth.backend import OAuthBackend + + +@login_notrequired +def show_login_page(request): + """Used by the non-jframe login""" + redirect_to = request.REQUEST.get('next', '/') + is_first_login_ever = OAuthBackend.is_first_login_ever() + + request.session.set_test_cookie() + return render('oauth-login.mako', request, { + 'action': urlresolvers.reverse('oauth_login'), + 'next': redirect_to, + 'first_login_ever': is_first_login_ever, + 'login_errors': request.method == 'POST', + 'socialGoogle': liboauth.conf.CONSUMER_KEY_GOOGLE.get() != "" and liboauth.conf.CONSUMER_SECRET_GOOGLE.get() != "", + 'socialFacebook': liboauth.conf.CONSUMER_KEY_FACEBOOK.get() != "" and liboauth.conf.CONSUMER_SECRET_FACEBOOK.get() != "", + 'socialLinkedin': liboauth.conf.CONSUMER_KEY_LINKEDIN.get() != "" and liboauth.conf.CONSUMER_SECRET_LINKEDIN.get() != "", + 'socialTwitter': liboauth.conf.CONSUMER_KEY_TWITTER.get() != "" and liboauth.conf.CONSUMER_SECRET_TWITTER.get() != "" + }) + + + +@login_notrequired +def oauth_login(request): + + if 'social' not in request.GET: + raise Exception(_("Invalid request: %s") % resp) + else: + url=OAuthBackend.handleLoginRequest(request) + + return HttpResponseRedirect(url) + + +@login_notrequired +def oauth_authenticated(request): + + access_token = OAuthBackend.handleAuthenticationRequest(request) + if access_token == "": + login_failed_url = '/' + return HttpResponseRedirect('{loginfailed}'.format(loginfailed = login_failed_url)) + user = authenticate(access_token = access_token) + login(request, user) + redirect_to = request.REQUEST.get('next', '/') + return HttpResponseRedirect(redirect_to) -- 1.8.4