/*
* Copyright (C) 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package apps.provisioning.server.apis;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.List;
import apps.provisioning.config.ConfigData;
import apps.provisioning.server.account.UsernameManager;
import apps.provisioning.server.account.data.UsernameDataSource;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.admin.directory.Directory;
import com.google.api.services.admin.directory.model.User;
import com.google.api.services.admin.directory.model.UserName;
import com.google.api.services.admin.directory.model.Users;
/**
* Manages the Admin SDK service.
*/
public class GoogleDirectory extends GoogleClient implements UsernameDataSource {
private GoogleCredential credential;
private Directory directory;
/**
* Represents the administrator customerId.
*
* @link https://developers.google.com/admin-sdk/directory/v1/reference/users/list
*/
private final String CUSTOMER_ID = "my_customer";
/**
* Number of users that can be retrieved per each API call. Maximum is 500. Acceptable values are
* 1 to 500.
*
* @link https://developers.google.com/admin-sdk/directory/v1/reference/users/list
*/
private final int MIN_RESULTS = 1;
private final int MAX_RESULTS = 500;
/**
* Constructor used for testing only.
*/
public GoogleDirectory() {
super();
}
/**
* Initializes Admin SDK credentials.
*
* @throws GeneralSecurityException
* @throws IOException
*/
public GoogleDirectory(ConfigData config) throws GeneralSecurityException, IOException, Exception {
super(config);
credential = getCredentialForServiceAccount(serviceAccountEmail, keyPath);
directory = createAuthorizedClient(appName, credential);
// Forces Google Apps authentication (it happens in the first API call) to prevent delay in the
// next API call (up to 30 seconds).
directory.users().list().setCustomer(CUSTOMER_ID).setMaxResults(MIN_RESULTS).execute();
}
public boolean exists(String username) {
return getUser(username) != null;
}
/**
* Retrieves the requested username from Google Apps.
*
* @param username Username without domain.
* @return Whether it is not found, it returns null
*/
private User getUser(String username) {
try {
return directory.users().get(getEmail(username)).execute();
} catch (IOException e) {
return null;
}
}
/**
* Retrieves the basic information of all the users from the configured domain.
*
* @return List with all the users.
* @throws Exception
*/
public void copyToDataSource(UsernameDataSource dataSource) throws Exception {
Directory.Users.List request = directory.users().list();
// This constant applies to every domain or multi domain Google Apps
// account.
request.setCustomer(CUSTOMER_ID);
request.setMaxResults(MAX_RESULTS);
request.setDomain(domain);
// Get all users
do {
ArrayList<String> usernames = new ArrayList<String>();
Users currentPage = request.execute();
List<User> users = currentPage.getUsers();
for (int i = 0; i < users.size(); i++) {
usernames.add(users.get(i).getPrimaryEmail().split("@")[0]);
}
dataSource.insertMultiple(usernames);
request.setPageToken(currentPage.getNextPageToken());
} while (request.getPageToken() != null && request.getPageToken().length() > 0);
}
/**
* Creates a user in Google Apps Diretory.
*
* @param username Username without domain.
* @param firstname First name
* @param lastname Last name
* @param password Password with 8 characters or longer.
* @return The created user.
* @throws IOException
* @throws Exception When values are null, empty, shorter or longer than allowed.
*/
public User createUser(String username, String firstname, String lastname, String password)
throws IOException, Exception {
if (username == null || firstname == null || lastname == null || password == null) {
throw new Exception("Null values are not allowed.");
}
if (username.isEmpty() || firstname.isEmpty() || lastname.isEmpty() || password.isEmpty()) {
throw new Exception("All the parameters must be filled.");
}
if (username.length() > UsernameManager.MAX_USERNAME_LENGTH
|| firstname.length() > UsernameManager.MAX_NAME_LENGTH
|| lastname.length() > UsernameManager.MAX_NAME_LENGTH
|| password.length() > UsernameManager.MAX_PASSWORD_LENGTH) {
throw new Exception(
"One of the fields exceds the maximum length. 60 (firstname,lastname), 64 (username),"
+ " 100 (password)");
}
if (password.length() < UsernameManager.MIN_PASSWORD_LENGTH) {
throw new Exception("Password must have at least 8 characters.");
}
User user = new User();
UserName name = new UserName();
name.setGivenName(firstname);
name.setFamilyName(lastname);
user.setName(name);
user.setPrimaryEmail(getEmail(username));
user.setPassword(password);
return directory.users().insert(user).execute();
}
public void insert(String username) throws Exception {
throw new Exception("insert is not implemented in GoogleDirectory. Call createUser instead.");
}
public void insertMultiple(ArrayList<String> usernames) throws Exception {
throw new Exception(
"insertMultiple is not implemented in GoogleDirectory. Call createUser instead.");
}
/**
* Deletes a user.
*
* @param username Username without domain.
* @throws IOException
*/
public void remove(String username) throws IOException {
directory.users().delete(getEmail(username)).execute();
}
/**
* Appends the configured domain to username.
*
* @param username Username without domain.
* @return Email
*/
private String getEmail(String username) {
return username + "@" + domain;
}
}