check if an email id exists in the AdminDirectory.Users - javascript

Is there way to check if an email id exists in the AdminDirectory.Users or not? I know that https://developers.google.com/admin-sdk/directory/v1/reference/users/get retrieves all the users, is there a query like exists(from sql) in Google apps script?

The .get() function is used to get an individual user.
To test is the user existis or not you can use .get() in a try catch
This function will return true if the user exists and false if not.
function lookupUser(email){
var isUser
try{
var user = AdminDirectory.Users.get(email);
isUser = true;
} catch (e){
isUser = false;
}
return isUser;
}

If we base the methods in Directory API, there's Users.list which has a 'query' property. The valid queries you can perform are found in Search for users and sure enough there's an 'email' value.
Play around with that and try it in Apps Script's List all users.

Related

Understanding apps script api calls?

This script works. It has user id 4 which I am adding their email address to check the google admin API. The resolved column[10] is where managers approve requests. Because some of these usernames are not correctly entered, I was looking for a way to check if they were actually correct user ids. Both .setValue() lines work under try and catch, they also error on same users. I am trying to understand where the actual validation is happening. I guess I am trying to figure how the script knows to check the primary email address? Hope that makes sense.
function getNames() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet = ss.getActiveSheet();
var values = sheet.getDataRange().getValues();
for(var i = 1; i < values.length; i++){
var data = values[i];
var resolved = data[10];
if(resolved === ""){
try{
var email = sheet.getRange(1+i,4).getValues() + '#buisness.com'
var user = AdminDirectory.Users.get(email);
var name = user.name.fullName;
sheet.getRange(1+i, 5).setValue('Yes this is an employee');//How does this work?
//sheet.getRange(1+i, 5).setValue(name);//This works which I expect
}
catch(errors){
sheet.getRange(1+i,5).setValue(errors);
}
}
}
}
The validation happens through the AdminDirectory.Users.get() function with the help of the try and catch statements.
Admin SDK Directory Service/Get User
This API function gets a user by their email address. If the email address exists, all their data will be logged as a JSON string. Otherwise, it will return an error.
Try and Catch
The try and catch statements belong under JavaScript Errors. The try statement will run a code block that you place in it. If it encounters any error, it will trigger the catch statement (which usually displays the error messages.
Your Code
Your code checks for the validity of the email address with the use of the AdminDirectory.Users.get() function inside the try statement. If the function fails, it returns an error which triggers the catch statement (which usually displays the error messages).
References:
Admin SDK Directory Service/Get User
JavaScript Errors

storing user data in firebase with unique identifiers

I have a publicly accessible app. No sign in is required but I need a way to store user data in the database as an object associated with a unique key.
From what I understand, tokens would be a way to get a unique identifier from firebase(??)
I tried creating an anonymous user and getting a token like this:
let user = firebase.auth().signInAnonymously();
user.getIdToken(true);
I expected getIdToken to return a string but I get an object.
So...
1) Are tokens what I want to do this?
2) If so how can I get a new token as a string?
Use the following code as a global listener on ur page to check if the sign-in is successful:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
var isAnonymous = user.isAnonymous;
var unique_id = user.uid;
} else {
// User is signed out.
// ...
}
});
This snippet has been taken from the Firebase Anonymous Auth link: Click Here to open link.
For some reason I was trying to set up a binding to sync my app with Firebase, which I just realized I don't need at all! (I just need to push the data at the end of the poll).
Of course as soon as removed that requirement it was as simple as:
firebase.database().ref().push().set(myData);
When using the push() method, Firebase automatically generates a unique key which is all I need...

Check if Firebase Facebook user exists without creating a user starting from anonymous user

In Firebase I need to check if a Facebook user exists without creating the user. Initially the user is anonymous, and they try to login with Facebook. I want this to fail if the Facebook account is not already linked to a user in my system. It won't be linked to the current user because they are anonymous,
If I use Auth.signInAndRetrieveDataWithCredential I expected a "auth/user-not-found" error, but instead the user is simply created. Is this a bug or expected?
let credential = firebase.auth.FacebookAuthProvider.credential(
event.authResponse.accessToken)
firebase.auth().signInAndRetrieveDataWithCredential(credential).then( (userCredential) => {
let user = userCredential.user
app.debug("DEBUG: Existing user signed in:"+user.uid)
this.loginSuccess(user)
}).catch( (err) => {
app.error("ERROR re-signing in:"+err.code)
$("#login_status_msg").text(err)
})
If I use User.reauthenticateAndRetrieveDataWithCredential instead I get the error "auth/user-mismatch" which makes sense because user is currently anonymous. However, I was expecting "auth/user-not-found" may be thrown instead if the credential doesn't exist, but that doesn't happen.
I don't see a way to take my anonymous user, have them login with Facebook and then see if another user is already linked to that Facebook credential without creating the user if it doesn't exist.
If you're wondering why? My scenario is:
The system allows anonymous users
A user logs in, then converts to a logged in user by registering with Facebook.
App uninstall
App reinstall
User starts up the app and is initially anonymous.
They try and login with Facebook again. At this point I want to stop them from creating a user if they don't have one already. If they have a user ID already, the code works fine and changes their anonymous account ID to the original user ID which is good.
I found a solution! It wasn't too hard to implement, but it does seem hacky.
So we know that when using signInAndRetrieveDataWithCredential(cred) for facebook login, the account is created even if it does not exist yet. To solve this, we need to make sure that we handle the following three things:
Detect if the account is new
Delete the current account that was created by firebase
Throw an error to get out of the current flow and return to wherever you were before.
I just implemented and tested this solution, and it seems to work great:
// ... do your stuff to do fb login, get credential, etc:
const userInfo = await firebase.auth().signInAndRetrieveDataWithCredential(credential)
// userInfo includes a property to check if the account is new:
const isNewUser = _.get(userInfo, 'additionalUserInfo.isNewUser', true)
// FIRST, delete the account we just made.
// SECOND, throw an error (or otherwise escape the current context.
if (isNewUser) {
firebase.auth().currentUser.delete()
throw new Error('Couldn\'t find an existing account.')
}
// If the user already exists, just handle normal login
return userInfo.user
The reason I did this was to ensure that users had to go through the "create account flow" in my app. Your case would be really easy to implement as well, something like the following:
let credential = firebase.auth.FacebookAuthProvider.credential(event.authResponse.accessToken)
firebase.auth().signInAndRetrieveDataWithCredential(credential)
.then(userCredential => {
const isNewUser = userCredential.additionalUserInfo.isNewUser
if (isNewUser) {
firebase.auth().currentUser.delete()
// The following error will be handled in your catch statement
throw new Error("Couldn't find an existing account.")
}
// Otherwise, handle login normally:
const user = userCredential.user
app.debug("DEBUG: Existing user signed in:"+user.uid)
this.loginSuccess(user)
}).catch( (err) => {
app.error("ERROR re-signing in:"+err.code)
$("#login_status_msg").text(err)
})
You can use linkAndRetrieveDataWithCredential:
let credential = firebase.auth.FacebookAuthProvider.credential(
event.authResponse.accessToken);
anonymousUser.linkAndRetrieveDataWithCredential(credential).then( (userCredential) => {
// Firebase Auth only allows linking a credential if it is not
// already linked to another account.
// Now the anonymous account is upgraded to a permanent Facebook account.
}).catch( (err) => {
// Check for code: auth/credential-already-in-use
// When this error is returned, it means the credential is already
// used by another account.
})
You can use the method fetchSignInMethodsForEmail to check if an specific email is already associated to an specific provider or not. Doing this you will be able to check if one if the SighInMethods of the email associated to your user contains Facebook.com or not.
I show you below an example about how I manage this cases on my application. I'm using an RxJavaWrapper on my code, but you will understand the point of how to manage it:
RxFirebaseAuth.fetchSignInMethodsForEmail(authInstance, email)
.flatMap { providerResult ->
if (!providerResult.signInMethods!!.contains(credential.provider)) {
return#flatMap Maybe.error<AuthResult>(ProviderNotLinkedException(credential.provider))
} else {
return#flatMap RxFirebaseAuth.signInWithCredential(authInstance, credential)
}
}
.subscribe({ authResult ->
//Manage success
}, { error ->
//Manage error
})
First I check the providers associated to the email of the user(You can retrieve it from the provider)
If the list of SignInMethods contains my credential provider, I throw an error, if not, I call my signInWithCredential method to create the user.
Continue your workflow.
What I did to solve this problem without relying on the call to linkAndRetrieveDataWithCredential to fail and using the catch block to sign in the already existing user is to save the userID field that getCurrentAccessToken returns.
const { userID } = data;
this.props.setFacebookId(userID); // saves the userID on the server
I can later check if this userID already exists next time the user signs up with facebook.

meteor-useraccounts and alanning meteor-roles - Check role on sign-in

Is it possible to check users role on Sign in, and than if user is in role "admin" to display one page, and if is it in role "basic-user" to display another page ( go to another route).
Lets have a look at the Routes section of the documentation for the useraccounts:iron-routing package.
this should solve your problem
AccountsTemplates.configureRoute('signIn', {
redirect: function(){
var user = Meteor.user();
if (user && Roles.userIsInRole(user, ['admin'])) {
Router.go('admin');
}
else {
Router.go('home');
}
}
});
Be careful to check you can access the user roles field from the client side: lets check the allanning:roles official documentation
To define a default role for a user I use this:
// server
Accounts.onLogin(function(user) {
var user = user.user;
var defaultRole = ['student'];
if (!user.roles){
Roles.addUsersToRoles(user, defaultRole)
};
})
I'm using meteor-useraccounts and alanning meteor-roles packages and that work fine for me.
If I'm not outdated (and a look at http://docs.meteor.com/#/full/meteor_users suggests I'm not) there is no built in way for user roles. There should be some extensions for that task with which you could go and depending on what you choose you would have to check their documentation.
However it's not very hard to implement a own simple roles logic in Meteor:
First in your Accounts.onCreateUser function give your users object a new attribute role and assign them to a default role. If you don't have a Accounts.onCreateUser yet create one server side. It could look like something like this:
Accounts.onCreateUser(function(options, user) {
// Add an user roles array
user.roles = ["default-user"];
if (options.profile)
user.profile = options.profile;
return user;
}
Next you would need to implement some logic to add "admin" or whatever you like for trusted users to their roles array. That's up to you and for the beginning if you don't have dozens of admins you could also choose to do that manually in your MongoDB.
Now make sure you publish the new attribute of your user object to the currently logged in user. To do so make use of Meteor.publish with null as first parameter to address the current user like so:
Meteor.publish(null, function () {
return Meteor.users.find({_id: this.userId}, {fields: {
'roles': 1,
'profile': 1, // You probably want to publish the profile of a user to himself
// And here would be any other custom stuff you need
}});
});
And with that you are already in a state where you can do individual styling or routing client side. For example you could do something like this:
if (Meteor.user().roles.indexOf("admin") > -1) {
// Route for admins!
}
You could also parse through your array and add the user roles as class to your body element to for example only show certain elements to admins. This could be done this way:
Meteor.user().roles.forEach(function(role){
$('body').addClass(role);
});
Note that this will only be "cosmetic" but you can also implement real security with that as long as you do it server side. So if you want a Meteoer subscription or Meteor method only to be available for admins add something like this to it:
var requestingUser = Meteor.users.findOne({ '_id': this.userId});
if (!_.contains(requestingUser.roles, "admin")) {
// Terminate the pbulish function or Meteor method here when there is no "admin" role
return;
}
As said, this only works sever side and should be at the start of Meteor.publish functions or at the start of functions within Meteor.methods blocks.

LDAP - Find user by name only

I am not too familiar with LDAP, however I am working on authentication in a Node.js app, and the user credentials for the web app is going to be gotten from the organization's Windows domain.
I have LDAP lookups working (using the Passport.js Node module), however to make it work, I have to put the user's full-fledged DN into Node. For example, let's say:
My FQDN is mydomain.private.net.
My users are stored in an organizational unit, let's say staff.
Now, if I want to lookup user joe, I have to put this string into Node:
var username = 'CN=joe,OU=staff,DC=mydomain,DC=private,DC=net';
do i really have to keep track of all that?
What if my users are in two different organizational units? The client-side browser doesn't know that! It just knows:
username = 'joe';
password = 'xxxxx';
What if you try to log on as administrator? Administrators are always in a totally different OU by default.
Is there a way to reference an LDAP object by just the name and nothing else?
This is a general LDAP problem. You need to get a unique identifier from the user, and then look for it.
Typically this is what the uid attribute is used for. Active Directory may or may not have that populated, and generally relies on sAMAccountName which must be unique within the domain.
So you need a two step process.
1) Query for uid=joe or samAccountName=joe
2) Use the results to test a bind or password compare.
You would then use the DC=mydomain,DC=private,DC=net value as the root to search from.
(answer to my own question)
geoffc's answer was correct, and this is the working solution adapted to my Node.js app using the activedirectory npm module:
// First search for the user itself in the domain.
// If successfully found, the findUser function
// will return the full DN string, which is
// subsequently used to properly query and authenticate
// the user.
var AD = self.ADs[domain];
AD.findUser(username, function(err, user) {
if (err) {
cb(false, 'AD error on findUser', err);
return;
}
if (!user) {
cb(false, 'User does not exist', void 0);
} else {
username = user.dn;
AD.authenticate(username, password, function(err, authenticated) {
if (authenticated == false) {
cb(false, err, void 0);
return;
} else {
cb(true, 'Authenticated', void 0);
}
});
}
});

Categories