Enroll new user in 2-Step verification through the Google API - c#

We are using Google API to create new google accounts (users and their emails).
New requirement is that we should support 2-Step authentication enabled in admin.google.com (for sub-organization) and we need to enforce the rule.
Now comes the problem: If we create new user in this sub-org it will try to enforce 2-Step authentication and, as it is not setup, user will not be able to login to set it up. And admin cannot setup 2-step verification for the user.
Even more... I need to be able to setup users 2-step verification through the API.
Does workaround for this exist, or does anyone have any idea how to do it?
Any suggestions are welcome,
thanks
UPDATE 1
Thanks to Jay Lee's answer I am expanding a bit with working C# code using Google.Apis.Admin.Directory.directory_v1 SDK
private string GenerateVerificationCode(string userKey)
{
var _service = new DirectoryService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = _applicationName,
});
var generateVerificationCodesRequest = _service.VerificationCodes.Generate(userKey);
generateVerificationCodesRequest.Execute();
var verificationCodesRequest = _service.VerificationCodes.List(userKey);
var verificationCodes = verificationCodesRequest.Execute();
var verificationCode = verificationCodes.Items[0].VerificationCodeValue;
return verificationCode;
}

You can:
Make sure user is created in an OU where 2SV is forced. Set the orgUnitPath attribute when calling users.create()
Call VerificationCodes.generate() for the new user to create backup codes to get backup 2SV codes for the user.
Share the backup codes with the new user along with their password and instructions for first login and setup of 2SV.
User will be able to pass 2SV with the backup codes for first login. Then they can setup normal 2SV via SMS or app. You'll want to provide new users with a good set of detailed instructions for this process as it does complicate onboarding but it means they are secure on day one.

Related

Workspace Domain-wide Delegation with service account not working for one project, works for others

We have different projects on GCP we use them to access different Google APIs. Most of them for internal use only.
In this particular case, we have 2 projects, both use Service Account and both are allowed on Workspace Domain-wide Delegation on the same scopes. They are almost clones of each other.
I execute a simple request with the same code (Spreadsheet.Get()) with project 1 credentials it works. I execute the same request with project 2 credentials it doesn't work.
Since Workspace Domain-wide Delegation it's activated the spreadsheet its shared to my email and I connect to the API with my email too (works with project 1 so this is not the problem) (impersonating a user)
The only difference it's that one project has OAuth Consent Screen on external (only 100 users cause we use it internally only, anyways..) and the other one it's internal but this has nothing to do with this right?
Where the problem could come from? Do I need to recreate the project that doesn't work?
Here is the error message :
Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested
Edit to answer the comments but this code works depending on the service account we use
Generating the credentials:
internal static ServiceCredential GetApiCredentialsFromJson(string jsonCredentialsPath, string mailToMimic)
{
string jsonCertificate = File.ReadAllText(jsonCredentialsPath);
string privateKey = Regex.Match(jsonCertificate, #"(?<=""private_key"": "")(.*)(?="")").Value.Replace(#"\n", "");
string accountEmail = Regex.Match(jsonCertificate, #"(?<=""client_email"": "")(.*)(?="")").Value;
ServiceAccountCredential.Initializer credentials = new ServiceAccountCredential.Initializer(accountEmail)
{
Scopes = _scopes,
User = mailToMimic
}.FromPrivateKey(privateKey);
return new ServiceAccountCredential(credentials);
}
Using the credentials:
internal GoogleSheetService(ServiceCredential credentials)
{
SheetsService = new SheetsService(new BaseClientService.Initializer()
{
HttpClientInitializer = credentials
});
SheetsService.HttpClient.Timeout = TimeSpan.FromSeconds(100);
}
Client ID is allowed on the Drive, Ads and Spreadsheets scopes on the Workspace console.
The answer was simple, but we had to figure it out by ourselves.
The scopes you add in your app when you initialize the client need to be exactly the same scopes you added in the Google Admin wide-delegation page. Even if your app or part of your app don't need them all.
C# example:
private static readonly string[] _scopes = { DriveService.Scope.Drive, SheetsService.Scope.Spreadsheets, SlidesService.Scope.Presentations };
ServiceAccountCredential.Initializer credentials = new ServiceAccountCredential.Initializer(accountEmail)
{
Scopes = _scopes,
User = mailToMimic
}.FromPrivateKey(privateKey);
return new ServiceAccountCredential(credentials);
Here my app only needs SheetsService.Scope.Spreadsheets but I had to add DriveService.Scope.Drive and SlidesService.Scope.Presentations because the same client its used for other apps that need them.

Error Calling Calendar API: Principal must be an email address

We wrote a software more than 1 year ago to sync events from google calendars. It's been working since March 2018, but it suddendly stop working this months on every Gsuite instances we use for us and for our customers.
The problem is that we are using a service account to access calendar resources events via google CalendarAPI v3.
After authenticating with service account credentials , for every service call we now encounter the error:
"Error:\"invalid_request\", Description:\"Principal must be an email address\", Uri:\"\""
I cannot find an answer anywhere about this problem, it sounds like a policy change on Google service, but I cannot be sure about this.
It seems like Google API is complaining about service account email, that isn't actually a real valid email. It is in this format:
mydomain.com_(client_id)313.......#resource.calendar.google.com
Do you think the problem could be related to the service account email address?
And why it was working before April and now stop working?
One possible solution, not yet tried:
I sow it is possible to use "delegation" for the service acount.
What would happens if I try to use a valid user email and delegate it upon my service account?
/* function I use to authenticate my service account to Google Calendar
* service. serviceAccount is the email (Principal not working?) and json is
* the key generated for him.
*/
public void bindCalendarService(string json, string serviceAccount)
{
var cr = Newtonsoft.Json.JsonConvert.DeserializeObject<PersonalServiceAccountCred>(json);
ServiceAccountCredential xCred = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(cr.client_id, cr.token_uri)
{
Scopes = new string[] {
CalendarService.Scope.Calendar,
},
User = serviceAccount
}.FromPrivateKey(cr.private_key));
CalendarService calendarService = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = xCred
});
this.calendarService = calendarService;
}
you need to give access to unsecured apps on google account security,
try this : https://support.google.com/accounts/answer/6010255?hl=en
if it do not work talk to me.
I solve today the problem in onother way.
1) I tried to implement delegation like it is wxplained on:
https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority
It works.
2) Without delegation, I changed my metod posted avove in this way:
var credentialParameters = NewtonsoftJsonSerializer.Instance.Deserialize(json);
ServiceAccountCredential xCred = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(**credentialParameters.ClientEmail**)
{
Scopes = new string[] {
CalendarService.Scope.Calendar
},
User = serviceAccount, // service account's email
}.FromPrivateKey(credentialParameters.PrivateKey));
It works even in this way.
It is still a mistery why above code stopped working after 1 year.
Hope it will help someone
Thanks

How to get a Drive.v3.Data.User on drive api c#

I'm working on a dll with some drive methods and I have all working right now, every method works in a base Drive.service i get when the user authentificates.
I finished almost all of my methods unless the personal user data, I'm suposed to get it from Google.Apis.Drive.v3.Data.User which has a few methods that get it to me.
My problem is that i can't create a Data.User object who has the user info that has authorized me, I don't know how to get a Data.User object that contains the info from a specific user.
I solved it by creating a PlusService (like the DriveService i was using for drive but for g+)
PlusService service = new PlusService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Google Plus Sample",
});
return service;
for this i needed to add using Google.Apis.Plus.v1; and modifie my scope when i get my credential to:
new[] { DriveService.Scope.Drive,PlusService.Scope.UserinfoProfile, PlusService.Scope.UserinfoEmail}
I also needed to enable the g+ api on my google developer console
Once you have the PlusService you need to get an user, i used this to get the user autentified on the credential("me" get's you your current user):
Person user =serviceplus.People.Get("me").Execute();
With this user you are able to get a lot of information about the user, even his relation status :P
I hope this helps someone

BOX: Add Collaboration to a folder using AppUser user token

I am building an integration between my organization back-end systems and BOX.
One of the scenarios is that when certain event is happening inside my organization there is a need to create a folder in BOX and add collaboration objects to that folder (connect groups to the folder).
I have no problem to create the folder but when trying to create the collaboration I am getting the following error:
Box.V2.Exceptions.BoxException: Bearer realm="Service", error="insufficient_scope", error_description="The request requires higher privileges than provided by the access token."
I am using BOX SDK for .Net to interact with BOX.
The application I created in BOX is assigned to use AppUser User Type and I provided all the scopes that BOX allows me (All scopes except "Manage enterprise" which is disabled).
The code that fails is (C#):
var privateKey = File.ReadAllText(Settings.JwtPrivateKeyFile);
var boxConfig = new BoxConfig(Settings.ClientID, Settings.ClientSecret, Settings.EnterpriseID, privateKey, Settings.JwtPrivateKeyPassword, Settings.JwtPublicKeyID);
var jwt = BoxJWTAuth(boxConfig);
var token = jwt.AdminToken();
var client = jwt.AdminClient(token);
var addRequest = new BoxCollaborationRequest(){
Item = new BoxRequestEntity() {
Id = folderId,
Type = BoxType.folder
},
AccessibleBy = new BoxCollaborationUserRequest(){
Type = BoxType.#group,
Id = groupId
},
Role = "viewer"
};
var api = client.CollaborationsManager;
var task = api.AddCollaborationAsync(addRequest);
task.Wait();
When running this code but replacing the Admin Token with Developer Token generated from the Box Applicaiton Edit Page it works.
Any help is appreciated
OK, I had long discussion with BOX Technical team and here is the conclusion: Using AppUser is not the right choice for my scenario because it is limited only to the folders it creates. There is no way to bypass it.
The solution is:
1. Configure the Application to use standard user
2. Create User with administrative rights that will be used by the API to do activities in BOX. I named this user "API User"
3. Follow the oAuth 2 tutorial to generate access token and refresh token that the API .Net application can use instead of generating token for the AppUser. the oAuth 2 tutorial can be found at https://www.box.com/blog/get-box-access-tokens-in-2-quick-steps/
If the app user is a member of the group(s) you want to be able to access the folder then you shouldn't need to set up a collaboration, the users should just have access.

Google Apis v3 in ASP.Net - "Unauthorized client or scope in request"

Maybe I am simply not getting "it", with "it" being the overall setup needed to make this work.
I have a website that scrapes other sites for sporting events. I want to automatically create Google Calendar events from the results, so I want to give my Web Application Read/Write access on a Calendar in my GMail account.
I have been trying to wrap my head around this for a week now, but I can't get it to work and it is crushing my self-esteem as a developer.
The way I "understand" it is that I need a Google API v3 Service Account, because I don't need an API key for a particular user. Or do I need a Simple API key (instead of oAuth)?
Anyways, I went with the Service Account.
In my HomeController I am trying to GET a Calendar so I know it all works.
public void Calendar()
{
string serviceAccountEmail = "...#developer.gserviceaccount.com";
var certificate = new X509Certificate2(
Server.MapPath("~") + #"\App_Data\key.p12",
"notasecret",
X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential =
new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[]
{
CalendarService.Scope.Calendar
},
User = "MY-GMAIL-EMAIL" // Is this correct?
}
.FromCertificate(certificate));
BaseClientService.Initializer initializer = new BaseClientService.Initializer();
initializer.HttpClientInitializer = credential;
initializer.ApplicationName = "CALENDAR NAME"; // Correct?
var service = new CalendarService(initializer);
var list = service.CalendarList.List().Execute().Items; // Exception :-(
}
The error I am getting:
An exception of type 'Google.Apis.Auth.OAuth2.Responses.TokenResponseException' occurred in Google.Apis.dll but was not handled in user code
Additional information: Error:"unauthorized_client", Description:"Unauthorized client or scope in request.", Uri:""
So I tried a bunch of things in Google Calendar, like making it public, adding the service account email as a READ/WRITE user.
What do I need to do to authorize my Web Application so it can create events on my behalf?
I have done this with the service account in a similar post. I changed a bit of my code and got it working to list my calendars by switching a few things around. I can create events as well. I didn't add a user as you have done in the initializer, and under application name, it is the name of the application in the dev console. Make sure you name your application. Make sure your service account is shared with your account.
I slightly changed the list part of your code to this in mine and got back the my list of calendars.
var list = service.CalendarList.List();
var listex = list.Execute();
Check out my example at Google API Calender v3 Event Insert via Service Account using Asp.Net MVC

Categories