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).
Related
since anypoint platform url anypoint.mulesoft.com is publicly accessible anyone can access the resources. Is there anyway i can restrict access to my org users apart from creating access roles.
Can i create org specific url with org secific access so that others cant access?
Can put some network related restrictions?
I think you confusing two different things:
Accessing a public URL (ie https://anypoint.mulesoft.com)
Authorization inside your organization's account
You can not restrict access to a site that you don't own, it is publicly accessible and needs to be accessed by other users. It doesn't even make sense really. Would you attempt to restrict access by others to google.com or twitter.com (or their API URLs)? It is not the right approach and it is just not possible.
What makes sense however is to manage permissions inside your organization in Anypoint Platform. It means when an user belonging to your organization logs in you can manage what of the available roles are permissions that user will have. You can do that in the Access Management page. You can also create custom roles with specific permissions and teams to better organize your users.
As mentioned you are not able to change MuleSoft's main URL (ie https://anypoint.mulesoft.com), one option being to control from Access Management page, both mentioned by #aled
There are two main ways you can get what you need:
If your organization already has some MFA tool that requires you to be in your corporate VPN, you could use that MFA as the MFA for the Anypoint Platform e.g. Users will need Username/Password, connect to the VPN to be able to get access to the MFA generator/auth and then use that code to finish logging into the platform. As Admin in Anypoint Platform you can enforce EVERYONE to have MFA set up (keep in mind ClientApps authorization for your automation users)
If your company already has an Identity Provider you can configure identity management in Anypoint Platform to set up users for single sign-on (SSO). The fragments below extracted from the official docs external-identity:
After configuring identity management, you must add new SSO users using your external identity management solution and internal provisioning process. If you use the Invite User feature to add users to your organization after you have configured an identity provider, the credentials for these users are stored locally in your organization rather than with the identity provider.
Users that log in with SSO are new users to the system. If the new user has the same username as a user that already exists in your Anypoint Platform organization, the new user co-exists with the original user with the same username. Users with the same username are managed independently from one another.
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.
I'm planning on building a G suite integration with my existing SaaS site.
I want Gsuite admins to allow access for their organisation. So I only want "domain install" possible.
After this has been done users can be imported from Google into our application. Users should be able to use SSO to login but I don't want each user having to pass the consent screen.
I also want the app to have readonly access to the calendar of the user.
What is confusing for me: do I need to create a regular web app integration or a Service account integration? I don't really need offline access but I want to avoid all users having to grant access individually.
Here it says: The user sees the OAuth Consent screen only once; if you’re using a service account to allow a domain admin accept terms on behalf of the domain users, then the end users must never see the OAuth consent screen.
So does that mean only service accounts allow this?
Yes, using a service account you can install and authorize one app for all your domain user impersonating the admin account. In such a way, your users won't have to authorize the app individually.
You will have to enable domain wide delegation in order to impersonate the admin account when using a service account.
Reference
Service Account
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.
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.