I need to implement the following scenario:
com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload#getHostedDomain
).It is similar to "Find your friends" feature on Facebook. In this case I want to find all people, who use the same Google Apps domain.
Is it possible to do (both technically and with respect to their terms of use)?
Update 1 (28.08.2017 20:00 MSK):
I've tried to get a list of all users using an access token (gIdToken.payload.accessTokenHash
in the code fragment below):
internal open fun createJsonFactory(): JsonFactory = JacksonFactory.getDefaultInstance()
internal open fun createTransport(): HttpTransport = GoogleNetHttpTransport.newTrustedTransport()
internal open fun createVerifier(httpTransport: HttpTransport, jsonFactory: JsonFactory): GoogleIdTokenVerifier {
return GoogleIdTokenVerifier.Builder(httpTransport, jsonFactory)
.setAudience(listOf(clientId))
.build()
}
val idToken = req.queryParams("idtoken")
val httpTransport = createTransport()
val jsonFactory = createJsonFactory()
val verifier = createVerifier(httpTransport, jsonFactory)
val gIdToken = verifier.verify(idToken)
if ((gIdToken != null) && (gIdToken.payload != null)) {
val credential = GoogleCredential().setAccessToken(gIdToken.payload.accessTokenHash)
val directory = Directory.Builder(httpTransport, jsonFactory, credential)
.setApplicationName("Google Auth Test")
.build()
try {
directory.users().list().setCustomer(gIdToken.payload.subject).execute()
}
catch (ex:Throwable) {
ex.printStackTrace()
}
}
When I run directory.users().list().setCustomer(gIdToken.payload.subject).execute()
, I get the following error:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 401 Unauthorized
{
"code" : 401,
"errors" : [ {
"domain" : "global",
"location" : "Authorization",
"locationType" : "header",
"message" : "Invalid Credentials",
"reason" : "authError"
} ],
"message" : "Invalid Credentials"
}
at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:146)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:321)
I'm using following Google libraries:
<dependency>
<groupId>google-api-services</groupId>
<artifactId>admin-directory_v1</artifactId>
<version>1.22.0</version>
</dependency>
<dependency>
<groupId>com.google.gdata</groupId>
<artifactId>core</artifactId>
<version>1.47.1</version>
</dependency>
How can I fix the error above?
Update 2 (29.08.2017 11:39 MSK): Tried to use Contacts API
Attempt 1: Contacts API feed
import com.google.gdata.data.extensions.ContactFeed
fun readUsers2(gIdToken:GoogleIdToken, httpTransport: HttpTransport, jsonFactory:JsonFactory) {
val credential = GoogleCredential().setAccessToken(gIdToken.payload.accessTokenHash)
val service = ContactsService("Google Auth Test")
service.setOAuth2Credentials(credential)
val feedUrl = URL("https://www.googleapis.com/auth/contacts.readonly")
val resultFeed: ContactFeed = service.getFeed(feedUrl, ContactFeed::class.java)
}
Result: Exception "Unrecognized content type: text/plain" in
com.google.gdata.client.Service#parseResponseData(com.google.gdata.data.ParseSource, com.google.gdata.wireformats.input.InputProperties, java.lang.Class<E>)
, see
throw statement below.
private <E> E parseResponseData(ParseSource source, InputProperties inputProperties, Class<E> resultType) throws IOException, ServiceException {
Preconditions.checkNotNull("resultType", resultType);
AltFormat inputFormat = null;
String alt = inputProperties.getQueryParameter("alt");
if (alt != null) {
inputFormat = this.altRegistry.lookupName(alt);
}
if (inputFormat == null) {
inputFormat = this.altRegistry.lookupType(inputProperties.getContentType());
if (inputFormat == null) {
throw new ParseException("Unrecognized content type:" + inputProperties.getContentType());
}
}
Attempt 2: Contacts API query
fun readUsers3(gIdToken:GoogleIdToken, httpTransport: HttpTransport, jsonFactory:JsonFactory) {
val credential = GoogleCredential().setAccessToken(gIdToken.payload.accessTokenHash)
val service = ContactsService("Google Auth Test")
service.setOAuth2Credentials(credential)
val feedUrl = URL("https://www.googleapis.com/auth/contacts.readonly")
val query = Query(feedUrl)
val resultFeed = service.query(query, ContactFeed::class.java)
}
Result: Same exception as in attempt 2.
Update 3 (29.08.2017 13:04 MSK):
I tried to get a list of users using the API Explorer.
I got the 403
error. Details are given below.
Request:
GET https://www.googleapis.com/admin/directory/v1/users?domain={MYDOMAIN}&fields=users(emails%2Cid%2Cname)&key={YOUR_API_KEY}
Response:
403
- Show headers -
{
"error": {
"errors": [
{
"domain": "global",
"reason": "forbidden",
"message": "Not Authorized to access this resource/api"
}
],
"code": 403,
"message": "Not Authorized to access this resource/api"
}
}
Update 4 (30.08.2017 13:19 MSK):
Finally, I managed to get rid of authentication and authorization errors (in a test installation of a G suite app).
However, now the following calls return an empty list of users (without errors).
val directory = Directory.Builder(
NetHttpTransport(),
JacksonFactory.getDefaultInstance(),
credential)
.setApplicationName("Google Auth Test")
.build()
val users = directory.users().list()
You need to get sufficient permissions from the user to fetch the list of all users in the domain. Moreover, it will only work if logged in user is super admin of the domain.
You can get list of permissions here.