| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF 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. |
| */ |
| |
| /** |
| * A directive for displaying an arbitrary login form. |
| */ |
| angular.module('login').directive('guacLogin', [function guacLogin() { |
| |
| // Login directive |
| var directive = { |
| restrict : 'E', |
| replace : true, |
| templateUrl : 'app/login/templates/login.html' |
| }; |
| |
| // Login directive scope |
| directive.scope = { |
| |
| /** |
| * An optional instructional message to display within the login |
| * dialog. |
| * |
| * @type TranslatableMessage |
| */ |
| helpText : '=', |
| |
| /** |
| * The login form or set of fields. This will be displayed to the user |
| * to capture their credentials. |
| * |
| * @type Field[] |
| */ |
| form : '=', |
| |
| /** |
| * A map of all field name/value pairs that have already been provided. |
| * If not null, the user will be prompted to continue their login |
| * attempt using only the fields which remain. |
| */ |
| values : '=' |
| |
| }; |
| |
| // Controller for login directive |
| directive.controller = ['$scope', '$injector', |
| function loginController($scope, $injector) { |
| |
| // Required types |
| var Error = $injector.get('Error'); |
| var Field = $injector.get('Field'); |
| |
| // Required services |
| var $rootScope = $injector.get('$rootScope'); |
| var $route = $injector.get('$route'); |
| var authenticationService = $injector.get('authenticationService'); |
| var requestService = $injector.get('requestService'); |
| |
| /** |
| * A description of the error that occurred during login, if any. |
| * |
| * @type TranslatableMessage |
| */ |
| $scope.loginError = null; |
| |
| /** |
| * All form values entered by the user, as parameter name/value pairs. |
| * |
| * @type Object.<String, String> |
| */ |
| $scope.enteredValues = {}; |
| |
| /** |
| * All form fields which have not yet been filled by the user. |
| * |
| * @type Field[] |
| */ |
| $scope.remainingFields = []; |
| |
| /** |
| * Whether an authentication attempt has been submitted. This will be |
| * set to true once credentials have been submitted and will only be |
| * reset to false once the attempt has been fully processed, including |
| * rerouting the user to the requested page if the attempt succeeded. |
| * |
| * @type Boolean |
| */ |
| $scope.submitted = false; |
| |
| /** |
| * The field that is most relevant to the user. |
| * |
| * @type Field |
| */ |
| $scope.relevantField = null; |
| |
| /** |
| * Returns whether a previous login attempt is continuing. |
| * |
| * @return {Boolean} |
| * true if a previous login attempt is continuing, false otherwise. |
| */ |
| $scope.isContinuation = function isContinuation() { |
| |
| // The login is continuing if any parameter values are provided |
| for (var name in $scope.values) |
| return true; |
| |
| return false; |
| |
| }; |
| |
| // Ensure provided values are included within entered values, even if |
| // they have no corresponding input fields |
| $scope.$watch('values', function resetEnteredValues(values) { |
| angular.extend($scope.enteredValues, values || {}); |
| }); |
| |
| // Update field information when form is changed |
| $scope.$watch('form', function resetRemainingFields(fields) { |
| |
| // If no fields are provided, then no fields remain |
| if (!fields) { |
| $scope.remainingFields = []; |
| return; |
| } |
| |
| // Filter provided fields against provided values |
| $scope.remainingFields = fields.filter(function isRemaining(field) { |
| return !(field.name in $scope.values); |
| }); |
| |
| // Set default values for all unset fields |
| angular.forEach($scope.remainingFields, function setDefault(field) { |
| if (!$scope.enteredValues[field.name]) |
| $scope.enteredValues[field.name] = ''; |
| }); |
| |
| $scope.relevantField = getRelevantField(); |
| |
| }); |
| |
| /** |
| * Submits the currently-specified username and password to the |
| * authentication service, redirecting to the main view if successful. |
| */ |
| $scope.login = function login() { |
| |
| // Authentication is now in progress |
| $scope.submitted = true; |
| |
| // Start with cleared status |
| $scope.loginError = null; |
| |
| // Attempt login once existing session is destroyed |
| authenticationService.authenticate($scope.enteredValues) |
| |
| // Retry route upon success (entered values will be cleared only |
| // after route change has succeeded as this can take time) |
| .then(function loginSuccessful() { |
| $route.reload(); |
| }) |
| |
| // Reset upon failure |
| ['catch'](requestService.createErrorCallback(function loginFailed(error) { |
| |
| // Initial submission is complete and has failed |
| $scope.submitted = false; |
| |
| // Clear out passwords if the credentials were rejected for any reason |
| if (error.type !== Error.Type.INSUFFICIENT_CREDENTIALS) { |
| |
| // Flag generic error for invalid login |
| if (error.type === Error.Type.INVALID_CREDENTIALS) |
| $scope.loginError = { |
| 'key' : 'LOGIN.ERROR_INVALID_LOGIN' |
| }; |
| |
| // Display error if anything else goes wrong |
| else |
| $scope.loginError = error.translatableMessage; |
| |
| // Clear all remaining fields that are not username fields |
| angular.forEach($scope.remainingFields, function clearEnteredValueIfPassword(field) { |
| |
| // If field is not username field, delete it. |
| if (field.type !== Field.Type.USERNAME && field.name in $scope.enteredValues) |
| delete $scope.enteredValues[field.name]; |
| |
| }); |
| } |
| |
| })); |
| |
| }; |
| |
| /** |
| * Returns the field most relevant to the user given the current state |
| * of the login process. This will normally be the first empty field. |
| * |
| * @return {Field} |
| * The field most relevant, null if there is no single most relevant |
| * field. |
| */ |
| var getRelevantField = function getRelevantField() { |
| |
| for (var i = 0; i < $scope.remainingFields.length; i++) { |
| var field = $scope.remainingFields[i]; |
| if (!$scope.enteredValues[field.name]) |
| return field; |
| } |
| |
| return null; |
| |
| }; |
| |
| // Reset state after authentication and routing have succeeded |
| $rootScope.$on('$routeChangeSuccess', function routeChanged() { |
| $scope.enteredValues = {}; |
| $scope.submitted = false; |
| }); |
| |
| }]; |
| |
| return directive; |
| |
| }]); |