Can applications with Domain-Wide Delegation enabled do more than the scopes allow by impersonating a superadmin? - google-oauth

Applications in GSuite can have domain-wide delegation (DWD) enabled, allowing the application to access user data (and other domain data) without any interaction on the part of the users.
According to a Google Support article, it is implied that the application is limited by the scopes set on the application.
However, reading various responses on Stack Exchange regarding "user impersonation" makes me wonder about the validity of this. See:
Breno's response "The domain-wide delegation model allows a service account to impersonate a user and thus obtain the same privileges in the domain that the user identity + set of scopes granted to the application imply."
Kessy's and Gilfoyle's responses "...This means that the service account only has access to data from the account the application is impersonating...." and "...First and foremost: A service account is technically a superadministrator once DWD ..."
Edited question ("Solution")
There is nothing concrete, but it appears (possibly incorrectly) that once an application impersonates the "right" user with sufficient admin privileges, any required data can be accessed. I've trawled through the Google Support documentation, but there is very little about scopes with regards to impersonating users that I could find. I haven't the experience building such an application to know what to look for.
My questions:
(Q) Can applications with DWD enabled do more than the scopes allow by impersonating a superadmin? If not, if one of those scopes includes the authority to change the user password (e.g. https://www.googleapis.com/auth/admin.directory.user), doesn't that mean an application can bootstrap itself and add any other, needed scopes?
Alternatively, are applications with DWD limited by their scopes, even when impersonating a super admin?
I'm not a developer; I'm a system admin with very some light/informal dev experience, so I would be greatly appreciative if you could pitch your answers accordingly.

The privelleges that an impersonated account has are limited in two ways
The impersonation can only perform requests on user's behalf within the range of the scopes authorized in the Admin consoles under Security -> API controls
A certain application can only use the scopes that were given to the service account when creating a credentials object
In other words:
If you enable in the admin console e.g. the scope https://www.googleapis.com/auth/admin.directory.user.readonly for a specific service account, this service account - when impersonated - will only be able to VIEW users, not to perform any request what goes beyond the limits of https://www.googleapis.com/auth/admin.directory.user.readonly
Even if you enable the full https://www.googleapis.com/auth/admin.directory.user scope in the admin console, but when creating the service account credentials object, you pass it only https://www.googleapis.com/auth/admin.directory.user.readonly as a scope - within the frame of the specific application, the service account equally will not be able to perform requests going beyond the scope https://www.googleapis.com/auth/admin.directory.user.readonly
The assumption once an application impersonates the "right" user with sufficient admin privileges, any required data can be accessed is confusing.
It would be more correct to say once an application impersonates the "right" user with sufficient admin privileges, any required data can be accessed - IF THE RESPECTIVE SCOPES HAVE BEEN ENABLED IN THE ADMIN CONSOLE AND GRANTED TO THE SERVICE ACCOUNT CREDENTIALS OBJECT OF THE SPECIFIC APPLICATION.
As a general rule of thumb, you should avoid providing (both when working with and without service account) to generous scopes, it is better to provide several specific scopes, rather than one broad scope.

Related

Where should a Google Service Account be created? The App's domain? Or in each client's Domain?

Is a Service Account intended to be created in an application’s domain? Or in a clients G Suite Domain, on behalf of the application?
Background:
My company has a product (hereafter “The App”) which has several thousand organizations as clients, each potentially having their own Google domains. (hereafter “Organization Domain”)
We are looking to set up a sync between The App and the Organization Domain, for data that is common between The App and the Organization Domain, and want to use an OAuth2 connection, with a domain admin granting The App ‘domain-wide authority’ on behalf of their users, for offline syncing.
From the Service Account page:
... an account that belongs to your application instead of to an
individual end user. Your application calls Google APIs on behalf of
the service account, so users aren't directly involved.
and
G Suite domain administrators can also grant service accounts
domain-wide authority to access user data on behalf of users in the
domain.
Referencing the Cloud Platform Console Help Faq:
You can access data from your users' Google Cloud Platform projects by
creating a service account to represent your service, and then having
your customers grant that service account appropriate access to their
cloud data using IAM policies. Note that you might want to create a
service account per customer... (emphasis added)
It sounds like The App should be able to create a single Service Account, which all of our clients authenticate into for their Organization Domain.
The part that’s unclear:
In the Service Account page, the instructions for delegating domain wide authority seems to shift concerning where the Service Account is.
Before the instructions, it reads:
... first enable domain-wide delegation for an existing service
account in the Service accounts page ... with domain-wide delegation
enabled. Then, an administrator of the G Suite domain must complete
the following steps:
Afterwards, it reads
Your application now has the authority to make API calls as users in
your domain (to "impersonate" users). (emphasis added)
From what I’m reading, the first part reads "one Service Account for The App", while the later reads as "the service account is only able to access as a person on The App domain, rather than the Organization Domain."
Is a service account intended to be created in The App's domain? Or in the Organization Domain, on behalf of The App?
I have seen examples that have the Organization Domain admin create a service account, and then pass over the clientID/secret to the owners of The App… but I’m not sure that’s the correct approach for our scenario.
Related - Scope management:
The delegation steps have the Organization Domain admin manually add scopes.
We’d prefer to use the OAuth consent screen, which shows the scopes, and has our pages/policies linked.
Unfortunately, as far as my research has uncovered, it doesn’t look like that page is used in the Service Account authorization flow; just for other application types, which authenticate a single user, as opposed to an entire Organization Domain.
Is there a page I’ve missed in Google’s sea of documentation?
I think you are miss understanding the use of Service accounts.
Service accounts are dummy user accounts. They have their own drive account, calendar account and probably a few more. Service accounts are designed for use with back end applications server to server communication where there is no user interaction. Service accounts are preauthorized. You grant the service account access to the user data in your case by using domain wide dedication to the gsuite account. This way the service account would be able to for example send control all the users google calendar accounts.
This is why you dont need a consent screen. Another point with service accounts is you must control the data in order to set this up. If you dont control the data then you cant grant the service account access to that data.
You should be using Oauth2 if you want to access private user data owned by your customers.
As for the rest of your question is very broad and i am not really user where to start with it you might want to break it up into several questions. Take them one at a time. I am not sure i understand what it is you are trying to do so i dont think i can try to answer that part.

Multiple authentication levels in a RESTful API

Scenario
We are building a new RESTful API for our web application. This API will serve our mobile applications, our web application and authorised customers.
We are using Apigility to build the API and are making use of the OAuth2 implementation it provides.
Currently, our web application relies on a users table, with permissions assigned to each user. These users simply log-in using a web form, and the session is then stored and appropriate permissions checked upon access.
We want to be able to authenticate API access (such as our web app, and authorised customers), so no unauthorised access to the API can happen. However, we also want to authorize the permissions at a user level, therefore some sort of user authentication must also happen as well.
Any authorised access to the API may use a different user, so relying on a single user per client will not work, especially since the permissions are on a per user basis. We also do not want any user to be able to use the API without prior authentication, so wanted to avoid adding every user as a client to OAuth2.
For example:
The web app is authenticated with the API with two users using it:
UserA has user management permissions
UserB does not have user management permissions
Therefore, UserA can POST to /users and receive a 200 OK while UserB should receive a 403 Forbidden.
What we have tried
We have created an example application, and have successfully set up authentication using OAuth2 for the high-level clients and can make calls as expected. But we have not been able to create an authorization model for our users based on this.
We though adding a custom HTTP header with a user token that is provided after an authenticated call to /user/login. But we are not sure if this is the correct method.
The question
How can we both authenticate the high-level clients (such as our web app, or authorised customers) but then authorize access based on the user actually using the system?
You have a few options available to you:
Token-level permissions
You can provide different tokens for each user account, and tie permissions to the token. This runs the risk of the wrong tokens being mixed up with the wrong users. However, this also has the advantage of not having to maintain a user<->token relationship, as the permission is decided at the token level. How you decide which token to generate can be tricky.
User-level permissions
You can tie a user account to a token and that user can then be given read/write permissions. This reduces the risk of a user having a wrong token as they're linked. With this method, you can use the same method of token generation for all user accounts as the token is ignorant of the permission, but does allow them "access" to the API (thus preventing unauthorised access).
I've deliberately avoided mentioning specific types of authentication tokens, as these two concepts can apply to most of the popular choices on the web (token-based, OAuth based).
OAuth has no concept of Identity.
You should look into using OpenID Connect which is a profile on top of Oauth 2.0.

Why does a service account with delegated domain access still need impersonation?

I am considering using OAuth 2.0 service accounts and domain-wide delegation of authority to integrate our service with Google Apps. A particular use case is:
When Google Apps customer signs up for our service, pre-provision our service leveraging the customer's existing org structure or resources (orgunits, groups, devices, users, folders, files, etc.).
When the customer's Google Apps resources change, synchronize applicable changes to our service.
I found that when using service accounts, I need to specify the email address of an authorized super user for the domain that I'm querying, like this:
var cred = new ServiceAccountCredential( new ServiceAccountCredential.Initializer( "{SERVICEACCOUNTEMAIL}" )
{
Scopes = new[]
{
DirectoryService.Scope.AdminDirectoryOrgunitReadonly
},
User = "{USERTOIMPERSONATE#customergadomain.com}"
}.FromCertificate( x509cert ) );
if I want to e.g.
Query all orgunits or groups in the domain
Query all folders owned by the organization, or folders for a specific user
Ideally, I would not want to have to couple automated background processes on our server with a specific Google Apps user, in order to keep the resources in sync with changes that the domain's admin or users might incur on the Google Apps side.
I don't want to have to specify the user. So my main question is, am I using the correct authorization model for what I'm trying to do?
My second question is more of an aside. What is the purpose of requiring impersonation to use the Admin APIs, when delegation has already granted access to the domain's resources? In contrast to the normal OAuth 2.0 authorization workflow, I don't have to authorize on behalf of the user, I just have to specify her email address. Am I missing an intent of the service account / delegated access model?
The domain-wide delegation model allows a service account to impersonate a user and thus obtain the same privileges in the domain that the user identity + set of scopes granted to the application imply.
In the case of the APIs you're calling, only a domain administrator can access those APIs. By virtue of the scope you have been granted + the ability to impersonate such administrator, you can access those APIs.
If the task were to access a single resource owned by the administrator (say an organization's calendar), it'd be possible for the administrator to share that resource with the service account and then the service account might be able to impersonate itself to access that resource. However, in the case of an entire API, which represents many collections of resources, it is not feasible to use ACLs and the only practical approach is to grant the service account the ability to impersonate directly the administrator for specific API(s).

Provisioning "new" users with multiple trusted STSes

When using Windows Identity Foundation (WIF) with multiple Security Token Services (STS), is it possible to provision users before they first access the application?
For example, let's say I have a web site called BufferOverrun where users can login and ask/answer questions and I want to support authentication with external Google accounts. When a user first accesses the page, they have to authenticate with their Google account, then they can access the web application. In this scenario, there are two STSes, Google (for identity authentication) and a custom one for my application (for authorization).
How can I assign claims to a user before that users accesses the system?
Since the identity is owned externally to my application, I cannot assign claims directly to that identity (and I wouldn't want to anyway, as they would be application specific). But since the user has not accessed the system, I do not have an internal identity to assign claims to. I see two possible solutions:
Wait for a user to access the system (creating some default application-specific claims), then use some internal provisioning tool to modify those claims as desired.
Have the provisioning tool allow users to manually map a default identity claim (email address, for example) before that identity authenticates by manually typing it in, so that on first access if the identity asserts that claim, a specific set of application claims are granted.
I see a few issues with both 1 and 2. For 1, all users have some implicit access to the system, even if the default application claims allow no functionality. This seems to work great for something like stackoverflow where the initial account has a certain permission set, and as the user uses the systems, new claims are granted. However, this is likely not desirable for all applications. 2 is error prone, as it requires an admin to manually specify a claim.
In both cases above, how do I provision the identity which has access to actually use the provisioning tool (i.e., an admin account)?
For this, I envision that during application installation time, I require a user to authenticate and set the applicaton claims for that identity to be such that they have "administrative" privileges. Is this a good implementation?
Historically (I am now referring to an existing application), the application specifically interfaced with Active Directory only. The way this was handled was that there was a built-in admin account (not affiliated with AD) that allowed the admin user to first login. After authenticating with the admin application, that user could search AD for users/groups and provision them individually. Any user/group not provisioned by the admin would not have access to the system at all. I don't see this paradigm being applicable to using an external STS like Google, etc, so I am trying to conceive an architecture that would enable external STS systems. Retaining the ability to search the STS is desired, though not required. In practice, the two STSes involved would likely both be Active Directory using federated services.
Note: This is similar to this question and this question.
When using Windows Identity Foundation (WIF) with multiple Security Token Services (STS), is it possible to provision users before they first access the application?
The answer is yes, if you have a way of identitfying those users (e.g. their e-mail)
In this scenario, there are two STSes, Google (for identity authentication) and a custom one for my application (for authorization).
This is frequently used, but not necessarilly always the case. If you rely just on Google, then you could simply have the authorization code in the app itself (e.g. "AuthorizationManager" classes, etc). The value of another STS is that it can be a broker for multiple identities (e.g. Google, LiveID, Yahoo!, whatever) and you can do some authorization related transformations.
Since the identity is owned externally to my application, I cannot assign claims directly to that identity (and I wouldn't want to anyway, as they would be application specific).
Why not? You can define a rule that says:
"Anyone authenticated with Google is a 'reader' in App BufferOverrun". You can even say:
"someone#gmail.com is a 'reader' on BufferOverrun", before someone accesses the app.
You can still use the original approach (an out of band admin account for setup). Or you can also "bootstrap" config during provisioning defining which is the claim that will identify admin users.
Take a look at sample "Federation with Multiple Partners and ACS" (sample 7) in http://claimsid.codeplex.com
We do exactly that.

Accessing active directory from wpf application without having to request / resend credentials

I am writing a WPF application, and one feature I want to implement is the ability to display a list of computers in the domain. I have found some useful Active Directory code here:
http://www.codeproject.com/Articles/90142/Everything-in-Active-Directory-via-Csharp-NET-3-5-.aspx
Typically code examples dealing with AD seem to require the user's credentials to make requests. But it occurs to me that if you are running the application from a computer that is part of the domain, the user has already provided user credentials sufficient to access AD on that domain controller, when logging on to the system.
Is there some way that the user can access AD via my application without the app having to ask the user to reenter the same credentials again? I mean is there some kind of token that I can forward that indicates the user is already authenticated? I am concerned about the risks of having to store and transmit credentials securely when I don't have to.
Thanks for any advice.
I later discovered that if you are logged on to the domain, that is sufficient for you to access the active directory store, without having to supply further credentials or impersonate an admin. And in some cases you can also access it without being logged in at all.