{-# LANGUAGE QuasiQuotes, OverloadedStrings #-} module Happstack.Authenticate.OpenId.Controllers where import Control.Lens ((^.)) import Control.Monad.Trans (MonadIO(..)) import Data.Acid (AcidState) import Data.Acid.Advanced (query') import Data.Maybe (fromMaybe) import Data.Text (Text) import qualified Data.Text as T import Happstack.Authenticate.Core (AuthenticateState, AuthenticateURL, getToken, tokenIsAuthAdmin) import Happstack.Authenticate.OpenId.Core (GetOpenIdRealm(..), OpenIdState) import Happstack.Authenticate.OpenId.URL (OpenIdURL(BeginDance, Partial, ReturnTo), nestOpenIdURL) import Happstack.Authenticate.OpenId.PartialsURL (PartialURL(UsingGoogle, UsingYahoo, RealmForm)) import Happstack.Server (Happstack) import Language.Javascript.JMacro import Web.Routes openIdCtrl :: (Happstack m) => AcidState AuthenticateState -> AcidState OpenIdState -> RouteT AuthenticateURL m JStat openIdCtrl authenticateState openIdState = nestOpenIdURL $ do fn <- askRouteFn mt <- getToken authenticateState mRealm <- case mt of (Just (token, _)) | token ^. tokenIsAuthAdmin -> query' openIdState GetOpenIdRealm | otherwise -> return Nothing Nothing -> return Nothing return $ openIdCtrlJs mRealm fn openIdCtrlJs :: Maybe Text -> (OpenIdURL -> [(Text, Maybe Text)] -> Text) -> JStat openIdCtrlJs mRealm showURL = [jmacro| var openId = angular.module('openId', ['happstackAuthentication']); var openIdWindow; tokenCB = function (token) { alert('tokenCB: ' + token); }; openId.controller('OpenIdCtrl', ['$scope','$http','$window', '$location', 'userService', function ($scope, $http, $window, $location, userService) { $scope.openIdRealm = { srOpenIdRealm: `(fromMaybe "" mRealm)` }; // $scope.isAuthenticated = userService.getUser().isAuthenticated; // $scope.$watch(function () { return userService.getUser().isAuthenticated; }, function(newVal, oldVal) { $scope.isAuthenticated = newVal; }); $scope.openIdWindow = function (providerUrl) { // openIdWindow = window.open(`(showURL ReturnTo [])`, "_blank", "toolbar=0"); tokenCB = function(token) { var u = userService.updateFromToken(token); $scope.isAuthenticated = u.isAuthenticated; $scope.$apply(); }; openIdWindow = window.open(providerUrl, "_blank", "toolbar=0"); }; $scope.setOpenIdRealm = function (setRealmUrl) { $http.post(setRealmUrl, $scope.openIdRealm). success(function(datum, status, headers,config) { $scope.set_openid_realm_msg = 'Realm Updated.'; // FIXME -- I18N }). error(function (datum, status, headers, config) { $scope.set_openid_realm_msg = datum.error; })}; }]); openId.directive('openidGoogle', ['$rootScope', function ($rootScope) { return { restrict: 'E', replace: true, templateUrl: `(showURL (Partial UsingGoogle) [])` }; }]); openId.directive('openidYahoo', ['$rootScope', function ($rootScope) { return { restrict: 'E', replace: true, templateUrl: `(showURL (Partial UsingYahoo) [])` }; }]); openId.directive('openidRealm', ['$rootScope', function ($rootScope) { return { restrict: 'E', templateUrl: `(showURL (Partial RealmForm) [])` }; }]); |] {- openIdCtrlJs showURL = [jmacro| { //this is used to parse the profile function url_base64_decode(str) { var output = str.replace('-', '+').replace('_', '/'); switch (output.length % 4) { case 0: break; case 2: output += '=='; break; case 3: output += '='; break; default: throw 'Illegal base64url string!'; } return window.atob(output); //polifyll https://github.com/davidchambers/Base64.js } var happstackAuthentication = angular.module('happstackAuthentication', []); happstackAuthentication.factory('userService', ['$rootScope', function ($rootScope) { var defaultUser = { isAuthenticated: false, username: '', token: null }; var service = { userCache: defaultUser, setUser: function(u) { // alert('setUser:' + JSON.stringify(u)); userCache = u; localStorage.setItem('user', JSON.stringify(u)); }, getUser: function() { var item = localStorage.getItem('user'); if (item) { // alert('getUser: ' + item); var user = JSON.parse(item); return(user); } }, clearUser: function () { userCache = defaultUser; this.setUser(defaultUser); } }; if (!localStorage.getItem('user')) { service.clearUser(); } return service; }]); var openId = angular.module('openId', ['happstackAuthentication']); openId.controller('UsernamePasswordCtrl', ['$scope','$http','$window', '$location', 'userService', function ($scope, $http, $window, $location, userService) { $scope.isAuthenticated = userService.getUser().isAuthenticated; $scope.login = function () { $http. post(`(showURL Token [])`, $scope.user). success(function (datum, status, headers, config) { var encodedClaims = datum.token.split('.')[1]; var claims = JSON.parse(url_base64_decode(encodedClaims)); $scope.username_password_error = ''; var u = userService.getUser(); u.isAuthenticated = true; $scope.isAuthenticated = true; u.username = $scope.user.user; // FIXME: this should come from the token u.token = datum.token; userService.setUser(u); }). error(function (datum, status, headers, config) { // Erase the token if the user fails to log in userService.clearUser(); $scope.isAuthenticated = false; // Handle login errors here $scope.username_password_error = datum.error; }); }; $scope.logout = function () { userService.clearUser(); $scope.isAuthenticated = false; }; $scope.signupPassword = function () { $scope.signup.naUser.userId = 0; $http. post(`(showURL (Account Nothing) [])`, $scope.signup). success(function (datum, status, headers, config) { $scope.signup_error = 'Account Created'; // FIXME -- I18N $scope.signup = {}; }). error(function (datum, status, headers, config) { $scope.signup_error = datum.error; }); }; $scope.changePassword = function (url) { var u = userService.getUser(); if (u.isAuthenticated) { $http. post(url, $scope.password). success(function (datum, status, headers, config) { $scope.change_password_error = 'Password Changed.'; // FIXME -- I18N $scope.password = {}; }). error(function (datum, status, headers, config) { $scope.change_password_error = datum.error; }); } else { $scope.change_password_error = 'Not Authenticated.'; // FIXME -- I18N } }; $scope.requestResetPassword = function () { $http.post(`(showURL PasswordRequestReset [])`, $scope.requestReset). success(function (datum, status, headers, config) { $scope.request_reset_password_msg = datum; }). error(function (datum, status, headers, config) { $scope.request_reset_password_msg = datum.error; }); }; $scope.resetPassword = function () { var resetToken = $location.search().reset_token; if (resetToken) { $scope.reset.rpResetToken = resetToken; $http.post(`(showURL PasswordReset [])`, $scope.reset). success(function (datum, status, headers, config) { $scope.reset_password_msg = datum; }). error(function (datum, status, headers, config) { $scope.reset_password_msg = datum.error; }); } else { $scope.reset_password_msg = "reset token not found."; // FIXME -- I18N } }; }]); openId.factory('authInterceptor', ['$rootScope', '$q', '$window', 'userService', function ($rootScope, $q, $window, userService) { return { request: function (config) { config.headers = config.headers || {}; u = userService.getUser(); if (u && u.token) { config.headers.Authorization = 'Bearer ' + u.token; } return config; }, responseError: function (rejection) { if (rejection.status === 401) { // handle the case where the user is not authenticated } return $q.reject(rejection); } }; }]); openId.config(['$httpProvider', function ($httpProvider) { $httpProvider.interceptors.push('authInterceptor'); }]); // upAuthenticated directive openId.directive('upAuthenticated', ['$rootScope', 'userService', function ($rootScope, userService) { return { restrict: 'A', link: function (scope, element, attrs) { var prevDisp = element.css('display'); $rootScope.$watch(function () { return userService.getUser().isAuthenticated; }, function(auth) { if (auth != (attrs.upAuthenticated == 'true')) { element.css('display', 'none'); } else { element.css('display', prevDisp); } }); } }; }]); // upLoginInline directive openId.directive('upLoginInline', ['$rootScope', 'userService', function ($rootScope, userService) { return { restrict: 'E', // replace: true, templateUrl: `(showURL (Partial LoginInline) [])` }; }]); // upChangePassword directive openId.directive('upChangePassword', ['$rootScope', '$http', '$compile', 'userService', function ($rootScope, $http, $compile, userService) { function link(scope, element, attrs) { $rootScope.$watch(function() { return userService.getUser().isAuthenticated; }, function(auth) { if (auth == true) { $http.get(`(showURL (Partial ChangePassword) [])`). success(function(datum, status, headers, config) { element.empty(); var newElem = angular.element(datum); element.append(newElem); $compile(newElem)(scope); }); } else { element.empty(); } }); } return { restrict: 'E', link: link // templateUrl: `(showURL (Partial ChangePassword) [])` // template: "
" // template: "
" }; /* return { restrict: 'E', templateUrl: `(showURL (Partial ChangePassword) [])` }; */ }]); // upRequestResetPassword directive openId.directive('upRequestResetPassword', [function () { return { restrict: 'E', // replace: true, templateUrl: `(showURL (Partial RequestResetPasswordForm) [])` }; }]); // upResetPassword directive openId.directive('upResetPassword', [function () { return { restrict: 'E', // replace: true, templateUrl: `(showURL (Partial ResetPasswordForm) [])` }; }]); openId.directive('upSignupPassword', [function () { return { restrict: 'E', // replace: true, templateUrl: `(showURL (Partial SignupPassword) [])` }; }]); } |] -}