Angular.js edit in place with password - angularjs

This is my example here
I want to add password protect, when i click to "Edit title".
How can i do it?
JS code:
function ClickToEditCtrl($scope) {
$scope.title = "Welcome to this demo!";
$scope.editorEnabled = false;
$scope.enableEditor = function() {
$scope.editorEnabled = true;
$scope.editableTitle = $scope.title;
};
$scope.disableEditor = function() {
$scope.editorEnabled = false;
};
$scope.save = function() {
$scope.title = $scope.editableTitle;
$scope.disableEditor();
};
}

Simply create a $scope.checkPassword (or something meaningful) function which shows a popup/modal/etc where the user can input the password and then make an ajax call to verify for the password. If the password entered is correct enable editor else do nothing. Or maybe you want to allow save password if the user authenticates successfully.
UPDATE:
I think password verification should be handled totally by the server. I would make a call to function that handles authentication before saving the password (on the server). So make sure that you send the password as a parameter with the save call.

Related

Removing a set users information on logout

Good day, am currently struggling to understand why I can not set a user value as null on logout. I have a method used to set the user information so it's accessed globally and a get method to get the users information later on but right now regardless of which user is logged in the previous user data remains.
This is my current service controller:
.factory('UserInfo', [function() {
var user;
return {
get: function(){
return user;
},
set: function(userInfo){
user = userInfo;
},
remove :function(){
user = null;
return user;
}
};
}
])
.factory('Authentication',['UserInfo',function(UserInfo){
return {
user: UserInfo.get()
};
}]);
The function that I am trying to calling out is the remove function in the UserInfo service. Any help will be appreciated.
A factory is a singleton, the first instance created gets used every single time you ask for it. So if you do the following:
.factory('Authentication',['UserInfo',function(UserInfo){
return {
user: UserInfo.get()
};
}]);
.controller('Blabla', ['Authentication', function(Authentication) {
var user = Authentication.user;
}]
you will set user equal to what UserInfo.get() returns at that point. So everytime you call Authentication.user() it will return the same object, regardless of what the UserInfo actually contains.
You can solve this by passing a function instead of the function result. Like so:
.factory('Authentication',['UserInfo',function(UserInfo){
return {
user: UserInfo.get
};
}]);
.controller('Blabla', ['Authentication', function(Authentication) {
var user = Authentication.user();
}]
notice how the () (parenthesis) are gone on the UserInfo.get and they're added on the Authentication.user().

Why does my Angular's ng-show call only get updated on the second click using Firebase?

I am working on a sign-in page using AngularJS and Firebase. So far, most of my code has been working fine, until I tried to add notifications. It seems that the won't display when ng-show says that they should. It takes two clicks to work, which should never be the case.
As of now, I have the following button.
<button ng-click="cna()" type="button" class="btn btn-success ban block" style="width:50%">Create New Account</button>
The cna() function is the Create New Account function. This looks like:
create($scope.email, $scope.password);
The create() method looks like:
function create(email, password) {
firebase.auth().createUserWithEmailAndPassword(email,password).catch(function(error){
var errorCode = error.code;
var errorMessage = error.message;
console.log(errorCode+":"+errorMessage);
$scope.failure = true;
$scope.success = false;
});
firebase.auth().onAuthStateChanged(function(user){
if(user){
$scope.success = true;
$scope.failure = false;
}else{}
});
}
Lastly, I have two notifications that are supposed to show up when $scope.success or $scope.failure are set to true. However, this only works on the second click which, as it should, fails. So, my problem here is that my Account is being created, but my GUI is not being notified until the second click. There shouldn't be a second click at all for it to work.
Finally, my notification code looks like:
<div class="alert alert-success" ng-show="success"><strong>Success!</strong> You made an account!</div>
<div class="alert alert-danger" ng-show="failure"><strong>Sorry!</strong> This user already exists...</div>
I have looked all of the web, and so far all I have found is something called AngularFire that may be a good alternative, but I'm not sure. If anyone can help me with my problem, I would really appreciate it!
If you update the scope in a callback function, AngularJS is not aware of that update. And that means it doesn't update the views. So while the data is updated, the views are not. That's also why when you click again (or in some other way force a refresh of the views), the data shows up.
The solution is to explicitly tell AngularJS that it needs to refresh the views by calling $timeout() or $apply().
function create(email, password) {
firebase.auth().createUserWithEmailAndPassword(email,password).catch(function(error){ $timeout(function() {
var errorCode = error.code;
var errorMessage = error.message;
console.log(errorCode+":"+errorMessage);
$scope.failure = true;
$scope.success = false;
})});
firebase.auth().onAuthStateChanged(function(user){
if(user){
$timeout(function() {
$scope.success = true;
$scope.failure = false;
});
}else{}
});
}
A lot of these type of cases are handled automatically if you use the standard binding library: AngularFire.
if you do not see any message after your first click (do you?), try to add success function to your promise:
function create(email, password) {
firebase.auth().createUserWithEmailAndPassword(email,password).then(function () {
// you may want to add some condition here
$scope.success = true;
}, function(error){
var errorCode = error.code;
var errorMessage = error.message;
console.log(errorCode+":"+errorMessage);
$scope.failure = true;
});
firebase.auth().onAuthStateChanged(function(user){
if(user){
$scope.success = true;
$scope.failure = false;
}else{}
});
}

Auth login test using protractor and Azure AD

I am trying to authnticate user with an e2e test. I am not able to get this working. The test never waits after the button click on Azure AD login page.
describe('angularjs homepage', function() {
var ptor = protractor.getInstance();
ptor.ignoreSynchronization = true;
it('should greet the named user', function() {
var driver = ptor.driver;
browser.driver.manage().window().setSize(1500, 1000);
browser.driver.get('https://test.azurewebsites.net/test-ui/');
driver.findElement(By.id("cred_userid_inputtext")).sendKeys("TestUser#test.onmicrosoft.com");
// Find the element that's ID attribute is 'pwd' (Password)
// Enter Password on the element found by the above desc.
driver.findElement(By.id("cred_password_inputtext")).sendKeys("23423421asdasd");
// Now submit the form. WebDriver will find the form for us from the element
ptor.findElement(By.id("cred_sign_in_button")).click();
browser.driver.sleep(50000);
expect(element(by.id('username')).getText()).toEqual("Test User");
});
Kindly help
I was able to login by clicking the button from waiting for loading after fill in the form.
driver.findElement(By.id("cred_password_inputtext")).sendKeys("23423421asdasd");
browser.driver.sleep(2000);
ptor.findElement(By.id("cred_sign_in_button")).click();
I figured out that the Azure AD login page needs are double click for the button. hence
var btn = ptor.findElement(By.id("cred_sign_in_button"));
btn.click();
btn.click();
worked for me.

What's the proper way to hide/show AngularJS, or any other single page application ui components based on authenticated user rights?

I have an application that uses Spring Security for server side authentication/authorization, Spring MVC for the REST server side endpoints, and AngularJS for view.
In the server side I've implemented all the filters needed for accesing all those REST endpoints, based on the user rights.
My question is, how should I approach making visible/hiding html elements, based on the authenticated USER rights?
For example I have in the view 3 buttons (button1, button2, button3). Each button has a corresponding USER RIGHT, that should make them visible/hidden. Let's call that rights USER_RIGHT1, USER_RIGHT2, USER_RIGHT3.
If the user has the right USER_RIGHT1 he should see in the view the button1, if he has the right USER_RIGHT2 he should see in the view the button2, and so on.
My approach was to have a list of the authenticated user rights in the client, and do something as the following example:
<div ng-if="rights contains USER_RIGHT1">
<button name="button1".... />
</div>
<div ng-if="rights contains USER_RIGHT2">
<button name="button2".... />
</div>
I am not sure if the authenticated user right list should be in the client.
How should I approach this problem ? Am I doing it correctly ?
My approach is basically what you suggest.
You could have a factory which stores the array of permissions of the user and has a function to check if a permission is in the array:
.factory('Auth', function() {
var permissions = [];
return {
allowed : function(permission) {
return _.contains(permissions, permission);
}
};});
Then you can have a directive, that shows/hides an element using the service:
.directive('allowed', function(Auth){
return {
link : function(scope, elem, attr) {
if(!Auth.allowed(attr.allowed)){
elem.hide();
}
}
};
});
So in your views you only have to do:
<div allowed="permission_name"> </div>
Security on the client i.e. in a browser is next to useless. However, it should be present to stop the average user from seeing something they shouldn't however the server should be the ultimate place security is carried out.
I'd create a quick directive to do the showing / hiding or UI components and have a authentication service to do the actual logic to determine if the user has the correct rights.
I'm actual about 60% of the way through writing an in depth article about authorisation in AngularJS on my blog. I'd check back in about a week and I should have it done - it might help you with route authorisation as well.
UPDATE: The blog post about angular route authorization and security can be found here
Basically the authorisation service would authorise the user with your backend service it would then store their application rights.
The directive would then use this service to determine if the user has enough rights to see the UI component.
I haven't tested the below code so you might need to debug it.
angular.module('myApp').factory('authService', [
function () {
var loggedInUser,
login = function (email, password) {
//call server and rights are returned
//loggedInUser is assigned
},
hasSecurityRoles = function (requiredRoles) {
var hasRole = false,
roleCheckPassed = false,
loweredRoles;
if (loggedInUser === undefined) {
hasRole = false;
} else if (loggedInUser !== undefined && requiredRoles === undefined) {
hasRole = true;
} else if (loggedInUser !== undefined && requiredRoles !== undefined) {
if (requiredRoles.length === 0) {
hasRole = true;
} else if (loggedInUser.permittedActions === undefined) {
hasRole = false;
} else {
loweredRoles = [];
angular.forEach(loggedInUser.permittedActions, function (role) {
loweredRoles.push(role.name.toLowerCase());
});
// check user has at least one role in given required roles
angular.forEach(requiredRoles, function (role) {
roleCheckPassed = roleCheckPassed || _.contains(loweredRoles, role.toLowerCase());
});
hasRole = roleCheckPassed;
}
}
return hasRole;
};
return {
login: login,
hasSecurityRoles: hasSecurityRoles
};
}
]);
angular.module('myApp').directive('visibleToRoles', [
'authService',
function (authService) {
return {
link: function (scope, element, attrs) {
var makeVisible = function () {
element.removeClass('hidden');
},
makeHidden = function () {
element.addClass('hidden');
},
determineVisibility = function (resetFirst) {
if (resetFirst) {
makeVisible();
}
if (authService.hasSecurityRoles(roles)) {
makeVisible();
} else {
makeHidden();
}
},
roles = attrs.visibleToRoles.split(',');
if (roles.length > 0) {
determineVisibility(true);
}
}
};
}
]);
You would then use it like this
<div visible-to-role="admin,usermanager">.....</div>
Rather than having a hard-coded list in your templates/pages you could retrieve the authenticated user right list from the server and load it in your scope and then do the same thing that you are doing.
If you are using ui-router this is possible by using the resolve property (that is pre-loading certain data possibly from the server before a controller is called).
This way you can only retrieve the rights for the user that is looking at the page rather than have all rights hard-coded in the client.

When page refresh, how to call back function in angularjs

I'm trying to maintain session after page refresh in angularjs using java. I have seen many examples but, i didn't find proper solution which exactly I'm looking for.
Please find below login snippet code, when i click on login button it is calling loginUser()function in LoginController
When i do page refresh it is going to LoginController but it is not going inside loginUser()function.
According to my knowledge until we call function, it doesn't goes inside of it.
When I do refresh how can i call back loginUser() function.
please help me out from these. Appreciated..Many thanks.
LoginController.js
function LoginController($scope, $http, $location, $rootScope,
userService, SessionIdService) {
$scope.user = {};
$scope.user.username = '';
$scope.user.password = '';
$rootScope.loginUser = function(username, password) {
$scope.resetError();
$http.post('/user/main/login/' + username, password).success(
function(login) {
if (login.sessionId === null) {
$scope.setError(login.status);
return;
} else {
$rootScope.userlogin = login.uname;
userService.setUserName(login.uname);
SessionIdService.setSessionId(login.sessionId);
$location.path("/home");
}
}).error(function() {
$scope.setError('Invalid user/password combination');
});
};
$scope.resetError = function() {
$scope.error = false;
$scope.errorMessage = '';
};
$scope.setError = function(message) {
$scope.error = true;
$scope.errorMessage = message;
$rootScope.sees = '';
$rootScope.userlogin = '';
};
};
app.js
app.run(function($rootScope, $location, SessionIdService) {
$rootScope.$on("$routeChangeStart", function(event, next, current) {
console.log("Routechanged... ");
if (SessionIdService.getSessionId == "true") {
if (next.templateUrl == "scripts/views/homescreen.html") {
$location.path("/home");
} else {
$location.path("/screen");
}
}
});
});
login.html
<input name="textfield" type="text" ng-model="user.username"/>
<input name="textfield" type="password" ng-model="user.password"/>
<button type="button" ng-lick="loginUser(user.username,user.password)">Login</button>
It is not clear to me why you want to call loginUser after page refresh. Isn't the user already logged in? I think what you want is to call the success function inside the loginIser. In that case, you need to embed that data as a global JS variable inside your Java template, and pass that to your controller somehow.
You probably want these to be run after refresh:
$rootScope.userlogin = login.uname;
userService.setUserName(login.uname);
SessionIdService.setSessionId(login.sessionId);
$location.path("/home");
So, in your Java template, do something like:
<script>window.UNAME = {% this comes from your database %};window.SESSIONID={% similar %}</script>
Then, call that function somehow with window.UNAME as input. (or in your controller, check for the existence of window.UNAME and call it immediately. Something like:
window.UNAME && function (name, sessionId) {
$rootScope.userlogin = uname;
userService.setUserName(uname);
SessionIdService.setSessionId(sessionId);
$location.path("/home");
) {
}(window.UNAME, window.SESSION_ID)
Some other recommendations (unrelated to your main problem probably):
First of, change $rootScope.loginUser = function(username, password) { to
$rootScope.loginUser = function() {
var username = $scope.user.username;
var password = $scope.user.password
since you already have access to username and password there. So, change ng-click="loginUser()".
Second, SessionIdService.getSessionId == "true" seems off, check should probably be just SessionIdService.getSessionId

Resources