如何使用Google使用Google的Directory API更改用户密码?

时间:2014-08-27 14:43:19

标签: java google-directory-api google-oauth-java-client

我要事先道歉,我可能会遗漏一些信息,让任何人都知道我的设置是正确的。请告诉我还需要指明的内容。 我在一所大学工作,我们通过Google托管学生电子邮件帐户。它经常发生在忘记密码并且必须重置密码的情况下。我们有一个页面可以设置密码,如果他们验证有关自己的足够信息。我们一直在使用的代码已被Google弃用,转而使用其Directory API。我的任务是转换这个旧代码:

//changes a password
@Override
public void reset ( final String username, final String password ) throws ResetException
{
    try
    {
        Validate.notEmpty( username );
        Validate.notEmpty( password );

        final AppsForYourDomainClient client = ClientFactory.getClient();  //admin-user account
        final UserEntry entry = client.retrieveUser( username );
        Validate.isTrue( !entry.getLogin().getSuspended(), "Account is suspended." );
        entry.getLogin().setPassword( password );
        client.updateUser( username, entry );
    }
    catch ( final Exception e )
    {
        throw new ResetException( e );
    }
}

使用他们的新API。我已经阅读了很多文档和几个例子,但它们似乎都没有帮助。我已通过管理控制台为我们的管理员帐户启用了Admin SDK,并注册了我的应用并从他们的开发者控制台获得了一个密钥,但我似乎无法获得任何返回我想要的请求。现在我只是想获得一个用户列表:

public void testList () throws Exception
{
    InputStream is = null;
    final String accessToken = getAccessToken();
    final NetHttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
    final JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
    final File p12 = new File( GoogleResetterTest.class.getClassLoader().getResource("ead05e56893a.p12").toURI() );
    GoogleCredential credential = new GoogleCredential.Builder().setTransport(httpTransport)
                                        .setJsonFactory(jsonFactory)
                                        .setServiceAccountId( SERVICE_ACCOUNT_EMAIL )
                                        .setServiceAccountScopes( PlusScopes.all() )
                                        .setServiceAccountPrivateKeyFromP12File( p12 )  //password: notasecret
                                        .setClientSecrets(CLIENT_ID, CLIENT_SECRET)
                                        .build();
    final Directory dir = new Directory.Builder( httpTransport, jsonFactory, credential)
                                                .setApplicationName( "API Project" )
                                                .build();
    final Directory.Users diruser = dir.users();
    final Directory.Users.List diruserlist = diruser.list().setDomain( EMAIL_DOMAIN );
    final HttpResponse response = diruserlist.executeUsingHead();
    is = response.getContent();
    StringWriter writer = new StringWriter();
    IOUtils.copy(is, writer, "UTF-8");
    String theString = writer.toString();
    IOUtils.closeQuietly( is );
}

在diruserlist.executeUsingHead();我得到了这个答复:

  

com.google.api.client.auth.oauth2.TokenResponseException:400错误请求   {     “错误”:“invalid_grant”   }

对我而言,这是一个非常无用的错误消息,因为似乎有4或5个部分可能出错导致该响应。

我可以帮助以为我让整件事变得太复杂了。我喜欢原始代码的简单性,对新API的一些回应批评它更复杂。有没有人必须这样做,并指出我正确的道路来解决这个问题?

1 个答案:

答案 0 :(得分:1)

我将回答我自己的问题并将其标记为已解决,而不是删除问题或进行编辑。

这里有一些事情在发生,有些事情我错了。主要是因为关于构建器的文档很差或根本不存在。这就是我必须做的事情:

在管理控制台上设置https://admin.google.com/

  1. 确保我尝试使用的帐户具有此域的超级管理员访问权限(管理员角色 - >超级管理员)
  2. 在“安全”标签中启用API访问。 (安全性 - > API参考 - > API访问 - >启用API访问
  3. 在开发者控制台(下方)
  4. 上进行设置
  5. 添加对我的应用的访问权限(安全性 - >高级设置 - >身份验证 - >管理OAuth客户端访问权限
  6. 从开发者控制台向我的客户端授予这些范围(不带方括号):
    • [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
  7. 并非所有这些范围都是必要的,但它是我启用的

    在开发者控制台上设置https://console.developers.google.com/

    1. 创建项目
    2. 启用项目管理SDK(API& auth - > API)
    3. 创建OAuth客户端作为服务帐户(API& auth - >凭据 - >创建新的客户ID)
    4. 将该客户端ID带回管理控制台(上面的步骤5)
    5. 下载我的java应用程序可以读取的p12键。 (API& auth - >凭证 - >生成新的P12密钥)
    6. 现在我终于可以写一些java了!

      import java.io.*;
      import java.net.*;
      import java.util.*;
      
      import java.security.GeneralSecurityException;
      import java.security.MessageDigest;
      
      import javax.xml.bind.DatatypeConverter;
      
      import com.google.api.services.admin.directory.*;
      import com.google.api.services.admin.directory.model.*;
      import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
      import com.google.api.client.http.javanet.NetHttpTransport;
      import com.google.api.client.json.jackson2.JacksonFactory;
      
      import org.apache.commons.lang.StringUtils;
      import org.apache.commons.lang.Validate;
      
      public class PasswordResetter
      {
          public void changePassword( final String username, final String newPassword ) throws Exception
          {
              final Directory dir = getDirectory();
              final User studentUser = updatePassword( getUser( dir, DOMAIN_NAME, username ), password );
              updateDirectory( dir, studentUser );
          }
      
          private Directory getDirectory() throws IOException, GeneralSecurityException, URISyntaxException
          {
              final NetHttpTransport httpTransport = new NetHttpTransport();
              final JacksonFactory jsonFactory = new JacksonFactory();
              final File p12 = new File( P12_FILENAME );
              final GoogleCredential credential = new GoogleCredential.Builder()
                                                                          .setTransport(httpTransport)
                                                                          .setJsonFactory(jsonFactory)
                                                                          .setServiceAccountUser( SUPER_USER_EMAIL )
                                                                          .setServiceAccountId( SERVICE_ACCOUNT_EMAIL_FROM_DEV_CONSOLE ) //the one that ends in "@developer.gserviceaccount.com"
                                                                          .setServiceAccountScopes( getCredentials() )
                                                                          .setServiceAccountPrivateKeyFromP12File( p12 )
                                                                          .build();
              return 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();
          }
      
          private 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 Users getUser( 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 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 void updateDirectory( final Directory dir, final User user ) throws IOException
          {
              final Directory.Users.Update updateRequest = dir.users().update( user.getPrimaryEmail(), user );
              updateRequest.execute();
          }
      }
      

      现在我有一个很好的方法让我的超级用户帐户只提供一个用户名(定义他们的电子邮件因此查询)和一个新密码,并为它们更改它。请注意,这不是完整的类,不能仅通过复制粘贴进行编译。

      我当然希望我没有跳过一步。我在我的游戏机中有一些额外的设置,我害怕在它破坏的情况下摆脱它。希望这将有助于将来的其他人。