瀏覽代碼

HUE-1882 [core] Adding some missing file for OAuth support

Update last two Twitter API default ini values
Romain Rigaux 11 年之前
父節點
當前提交
f970f38

+ 2 - 2
desktop/conf.dist/hue.ini

@@ -381,13 +381,13 @@
   ## 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_twitter=https://api.twitter.com/oauth/access_token
   ## 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_twitter=https://api.twitter.com/oauth/authorize
   ## 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=

+ 2 - 2
desktop/conf/pseudo-distributed.ini.tmpl

@@ -387,13 +387,13 @@
   ## 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_twitter=https://api.twitter.com/oauth/access_token
   ## 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_twitter=https://api.twitter.com/oauth/authorize
   ## 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=

+ 272 - 0
desktop/libs/liboauth/src/liboauth/backend.py

@@ -0,0 +1,272 @@
+#!/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 httplib2
+import json
+import urllib
+import cgi
+import logging
+import sys
+
+from django.contrib.auth import logout as auth_logout
+from django.contrib.auth.models import User
+from django.http import HttpResponseRedirect
+from django.utils.translation import ugettext as _
+
+from desktop.auth.backend import DesktopBackendBase
+from desktop.auth.backend import rewrite_user
+from useradmin.models import get_profile, get_default_user_group, UserProfile
+from hadoop.fs.exceptions import WebHdfsException
+
+import liboauth.conf
+
+try:
+  import oauth2 as oauth
+except:
+  pass
+
+
+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

+ 149 - 0
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/~"
+    )

+ 252 - 0
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 _
+%>
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="utf-8">
+  %if first_login_ever:
+    <title>${_('Hue - Sign up')}</title>
+  %else:
+    <title>${_('Hue - Sign in')}</title>
+  %endif
+
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <meta name="description" content="">
+  <meta name="author" content="">
+
+  <link href="/static/ext/css/bootplus.css" rel="stylesheet">
+  <link href="/static/ext/css/font-awesome.min.css" rel="stylesheet">
+  <link href="/static/css/hue3.css" rel="stylesheet">
+
+  <style type="text/css">
+    body {
+      padding-top: 80px;
+    }
+
+    #logo {
+      display: block;
+      margin-left: auto;
+      margin-right: auto;
+      margin-bottom: 30px
+    }
+
+    .login-content {
+      width: 400px;
+      display: block;
+      margin-left: auto;
+      margin-right: auto;
+    }
+
+    .login-content label {
+      margin-bottom: 20px;
+      font-size: 16px;
+    }
+
+    .login-content input[type='text'], .login-content input[type='password'] {
+      width: 90%;
+      margin-top: 10px;
+      font-size: 18px;
+    }
+
+    .login-content input {
+      width: 100%;
+      padding: 10px 16px;
+    }
+
+    hr {
+      border-top-color: #DEDEDE;
+    }
+
+    ul.errorlist li {
+      font-size: 13px;
+      font-weight: normal;
+      font-style: normal;
+    }
+
+    input.error {
+      border-color: #b94a48;
+      -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+      -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+      box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+    }
+
+    .well {
+      border: 1px solid #D8D8D8;
+      border-radius: 3px 3px 3px 3px;
+    }
+
+    .footer {
+      position: fixed;
+      bottom: 0;
+      background-color: #338BB8;
+      height: 4px;
+      width: 100%;
+    }
+	
+	.btn.btn-large {
+			min-width: 38%;
+			margin: 8px 0 0 0;
+			text-align: left;
+
+			/*......added from here......*/
+			min-height: 0;
+			height: auto;
+	}
+
+	.icons-only {
+			text-align: center;
+	}
+
+	.icons-only .btn.btn-large img {
+			margin-right: 0;
+	}
+
+	.icons-only .btn.btn-large span {
+			display: none;
+			text-align: center;
+	}
+
+	.icons-only .btn.btn-large {
+			min-width: 32px;
+			text-align: center;
+	}
+
+	.login-content h3 {
+			text-align: center;
+			margin: 0 0 -25px;
+			font-size: 18px;
+			color: silver;
+	}
+
+  </style>
+</head>
+
+<body>
+
+<div class="footer"></div>
+
+<div class="navigator">
+  <div class="pull-right">
+    <ul class="nav nav-pills">
+      <li id="jHueTourFlagPlaceholder"></li>
+    </ul>
+  </div>
+  <a class="brand nav-tooltip pull-left" href="#"><img src="/static/art/hue-logo-mini-white.png"
+                                                       data-orig="/static/art/hue-logo-mini-white.png"
+                                                       data-hover="/static/art/hue-logo-mini-white-hover.png"/></a>
+  <ul class="nav nav-pills pull-left hide" id="visit">
+    <li><a title="${_('Visit gethue.com')}" href="http://gethue.com">${_('Fell asleep? Visit us on gethue.com instead!')} <i class="fa fa-external-link-circle"></i></a></li>
+  </ul>
+</div>
+
+
+<div class="container">
+  <div class="row">
+    <div class="login-content">
+      <form method="POST" action="${action}" class="well">
+        <img id="logo" src="/static/art/hue-login-logo.png" data-orig="/static/art/hue-login-logo.png"
+             data-hover="/static/art/hue-login-logo-skew.png"/>
+
+        %if login_errors:
+            <div class="alert alert-error" style="text-align: center">
+              <strong><i class="fa fa-exclamation-triangle"></i> ${_('Error!')}</strong> ${_('Invalid username or password.')}
+            </div>
+        %endif
+
+        %if first_login_ever:
+            <div class="alert alert-block">
+              <i class="fa fa-exclamation-triangle"></i>
+            ${_('This is your first time logging in.')}
+              <strong>${_('You will become Hue superuser.')}</strong>.
+            </div>
+            <h3>Sign Up via</h3>
+            <hr/>
+        %else:
+            <h3>Sign In via</h3>
+            <hr/>
+        %endif
+            <div id="buttons_group" class="buttons-group">
+                %if socialGoogle:
+                    <span class="btn btn-large btn-primary google"><img src="/liboauth_static/art/icon-gplus.png"><span>Google</span></span>
+                %endif
+                %if socialFacebook:
+                    <span class="btn btn-large btn-primary facebook"><img src="/liboauth_static/art/icon-fb.png"><span>Facebook</span></span>
+                %endif
+                %if socialLinkedin:
+                    <span class="btn btn-large btn-primary linkedin"><img src="/liboauth_static/art/icon-linkedin.png"><span>Linkedin</span></span>
+                %endif
+                %if socialTwitter:
+                    <span class="btn btn-large btn-primary twitter"><img src="/liboauth_static/art/icon-twitter.png"><span>Twitter</span></span>
+                %endif
+            </div>
+        <input type="hidden" name="next" value="${next}"/>
+      </form>
+    </div>
+  </div>
+</div>
+
+<script src="/static/ext/js/jquery/jquery-2.0.2.min.js"></script>
+<script>
+  var $buttonsGroup = $("#buttons_group");
+  if($buttonsGroup.children().length > 2) {
+     $buttonsGroup.addClass("icons-only");
+  }
+
+  $(document).ready(function () {
+    var _skew = -1;
+    $("[data-hover]").on("mouseover", function () {
+      var _this = $(this);
+      _skew = window.setTimeout(function () {
+        _this.attr("src", _this.data("hover"));
+        $("#visit").removeClass("hide");
+      }, 3000);
+    });
+
+    $("[data-hover]").on("mouseout", function () {
+      $(this).attr("src", $(this).data("orig"));
+      window.clearTimeout(_skew);
+    });
+
+        $("input").css({"display": "block", "margin-left": "auto", "margin-right": "auto"});
+        $("span.google").bind('click', function () {
+          window.location.replace('/oauth/social_login/oauth?social=google');
+          return false;
+        });
+        $("span.facebook").bind('click', function () {
+          window.location.replace('/oauth/social_login/oauth?social=facebook');
+          return false;
+        });
+
+        $("span.linkedin").bind('click', function () {
+          window.location.replace('/oauth/social_login/oauth?social=linkedin');
+          return false;
+        });
+        $("span.twitter").bind('click', function () {
+          window.location.replace('/oauth/social_login/oauth?social=twitter');
+          return false;
+        });
+
+    $("ul.errorlist").each(function () {
+      $(this).prev().addClass("error");
+    });
+  });
+</script>
+</body>
+</html>

+ 27 - 0
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'),
+)
+
+

+ 89 - 0
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)