我有一个Java应用程序,允许用户重置GSuite的密码。我们不允许用户更改自己的密码,而是将他们重定向到Web应用程序,该应用程序允许他们更改两个Active Directory的密码,然后使用GSuite重置相同的密码。我遵循了复杂的安全方案,即在gsuite帐户中启用API,然后在Google Cloud环境中创建服务帐户,然后在GSuite中授权该服务帐户。我还在Gsuites中添加了一个用户超级管理员用户,该用户将用于此服务。请记住,该服务在服务器的后端工作,并且不能使用OAauth交互式授权。服务帐户已获得以下权限:
https://www.googleapis.com/auth/admin.directory.group
https://www.googleapis.com/auth/admin.directory.user
https://www.googleapis.com/auth/admin.directory.user.readonly
https://www.googleapis.com/auth/admin.directory.user.security
发生的事情是,当我尝试更改标准电子邮件用户的密码时,它可以正常工作,但是当我尝试以超级管理员角色重置密码时,它失败,并出现以下异常:
Exception in thread "main" com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
"code" : 403,
"errors" : [ {
"domain" : "global",
"message" : "Not Authorized to access this resource/api",
"reason" : "forbidden"
} ],
"message" : "Not Authorized to access this resource/api"
}
at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:150)
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:401)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1056)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:499)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:432)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:549)
at gsuite.updateDirectory(gsuite.java:111)
at gsuite.changePassword(gsuite.java:53)
at gsuite.main(gsuite.java:118)
以下是完整的来源:
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.admin.directory.Directory;
import com.google.api.services.admin.directory.DirectoryScopes;
import com.google.api.services.admin.directory.model.User;
import com.google.api.services.admin.directory.model.Users;
import javax.xml.bind.DatatypeConverter;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
public class gsuite {
/**
* Email of the Service Account
*/
private static final String SERVICE_ACCOUNT_EMAIL = "webapp@transactrxsecurity.iam.gserviceaccount.com";
private static Directory directory=null;
/**
* Path to the Service Account's Private Key file
*/
private static final String SERVICE_ACCOUNT_PKCS12_FILE_PATH = "/Users/manuelelaraj/Downloads/transactrxsecurity-0ad733208988.p12";
private static final String DOMAIN_NAME="somedomain.com";
private static final String SUPER_USER_EMAIL = "system@Somedomain.com";
private static final String SUPER_USER_PASSWORD="Strongpassword";
public static void changePassword( Directory dir, final String username, final String newPassword ) throws Exception
{
Users users=getGSuiteUser( dir, DOMAIN_NAME, username );
if (users.isEmpty())
{
}
final User UserToBeUpdated = updatePassword( users.getUsers().get(0), SUPER_USER_PASSWORD);
updateDirectory( dir, UserToBeUpdated );
}
private static Directory getDirectory() throws IOException, GeneralSecurityException, URISyntaxException
{
if (directory!=null)
{
return directory;
}
final NetHttpTransport httpTransport = new NetHttpTransport();
final JacksonFactory jsonFactory = new JacksonFactory();
final File p12 = new File( SERVICE_ACCOUNT_PKCS12_FILE_PATH );
final GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountUser( SUPER_USER_EMAIL )
.setServiceAccountId( SERVICE_ACCOUNT_EMAIL ) //the one that ends in "@developer.gserviceaccount.com"
.setServiceAccountScopes( getCredentials() )
.setServiceAccountPrivateKeyFromP12File( p12 )
.build();
directory= new Directory.Builder( httpTransport, jsonFactory, null)
.setHttpRequestInitializer( credential )
.setApplicationName( "API Project" ) //Not necessary, but silences a runtime warning using any not-blank string here
.build();
return directory;
}
private static List<String> getCredentials()
{
final List<String> toReturn = new LinkedList<String>();
toReturn.add( DirectoryScopes.ADMIN_DIRECTORY_GROUP );
toReturn.add( DirectoryScopes.ADMIN_DIRECTORY_USER );
toReturn.add( DirectoryScopes.ADMIN_DIRECTORY_USER_READONLY );
toReturn.add( DirectoryScopes.ADMIN_DIRECTORY_USER_SECURITY );
return toReturn;
}
private static Users getGSuiteUser( final Directory dir, final String domain, final String username ) throws Exception
{
Directory.Users.List diruserlist = dir.users().list()
.setDomain( domain )
.setQuery( "email:" + username );
return diruserlist.execute();
}
private static User updatePassword( final User user, final String password ) throws Exception
{
final MessageDigest md = MessageDigest.getInstance( "MD5" ); //I've been warned that this is not thread-safe
final byte[] digested = md.digest( password.getBytes( "UTF-8" ) );
final String newHashword = DatatypeConverter.printHexBinary( digested );
return user.setHashFunction("MD5") //only accepts MD5, SHA-1, or CRYPT
.setPassword( newHashword );
}
private static void updateDirectory( final Directory dir, final User user ) throws IOException
{
final Directory.Users.Update updateRequest = dir.users().update( user.getPrimaryEmail(), user );
updateRequest.execute();
}
public static void main(String[] args) throws Exception {
Directory dir=getDirectory();
//regular user works!!
changePassword(dir,"userwithsuperadmin@transactrx.com","MaherManuco99!!");
//changing password for admin fails!!!
changePassword(dir,"userwithsuperadmin@transactrx.com","MaherManuco99!!");
}
}