Restringir o e-mail de login com Google OAuth2.0 a um nome de domínio específico


90

Não consigo encontrar nenhuma documentação sobre como restringir o login ao meu aplicativo da web (que usa OAuth2.0 e APIs do Google) para aceitar apenas solicitações de autenticação de usuários com um e-mail em um nome de domínio específico ou conjunto de nomes de domínio. Eu gostaria de colocar na lista de permissões em vez de na lista de proibições.

Alguém tem sugestões sobre como fazer isso, documentação sobre o método oficialmente aceito de fazer isso ou uma solução alternativa fácil e segura?

Para registro, não sei de nenhuma informação sobre o usuário até que ele tente fazer login por meio da autenticação OAuth do Google. Tudo que recebo de volta são as informações básicas do usuário e o e-mail.


3
Estou pesquisando isso também. Tenho um aplicativo que quero que seja acessível apenas a pessoas que tenham uma conta em nosso domínio do Google Apps for Business. A implementação do Google OpenID pode ser mais apropriada para nós dois ...
Aaron Bruce

1
Como posso implementar o login do usuário de domínio usando google sdk e c #?
user1021583

1

1
Por favor, eu tenho uma recompensa oben nessa questão, então alguém pode me ajudar

Respostas:


42

Portanto, tenho uma resposta para você. Na solicitação oauth, você pode adicionar "hd = domain.com" e isso restringirá a autenticação aos usuários desse domínio (não sei se você pode fazer vários domínios). Você pode encontrar o parâmetro hd documentado aqui

Estou usando as bibliotecas API do google aqui: http://code.google.com/p/google-api-php-client/wiki/OAuth2, então tive que editar manualmente o arquivo /auth/apiOAuth2.php para este :

public function createAuthUrl($scope) {
    $params = array(
        'response_type=code',
        'redirect_uri=' . urlencode($this->redirectUri),
        'client_id=' . urlencode($this->clientId),
        'scope=' . urlencode($scope),
        'access_type=' . urlencode($this->accessType),
        'approval_prompt=' . urlencode($this->approvalPrompt),
        'hd=domain.com'
    );

    if (isset($this->state)) {
        $params[] = 'state=' . urlencode($this->state);
    }
    $params = implode('&', $params);
    return self::OAUTH2_AUTH_URL . "?$params";
}

Edit: Ainda estou trabalhando neste aplicativo e encontrei este, que pode ser a resposta mais correta para esta pergunta. https://developers.google.com/google-apps/profiles/


Eu não sabia sobre esse parâmetro. Você pode acessar o link para onde descobriu isso?
Jason Hall

Infelizmente, tive que obter a informação de um colega meu, não encontrei isso em nenhum lugar dos documentos do Google. Meu colega de trabalho acha que encontrou a referência na especificação OpenID e a experimentou aqui na especificação OpenAuth e parece funcionar. Suponho que use com cautela, uma vez que parece ser uma funcionalidade não documentada.
Aaron Bruce

31
Observação importante: embora você esteja especificando um hdparâmetro na createAuthUrlfunção, ainda precisará verificar se o usuário está fazendo login com o endereço de e-mail do seu domínio. É muito fácil alterar o parâmetro do link para permitir todos os endereços de e-mail e, posteriormente, obter acesso ao seu aplicativo.
VictorKilo de

1
Para a documentação do Google sobre o hduso do parâmetro, consulte developers.google.com/identity/work/it-apps E a referência do hdparâmetro URI pode ser encontrada developers.google.com/identity/protocols/… Em sinopse, o hdparâmetro deve ser visto como um filtro de exibição baseado em domínio para o Google Auth lado, mas ainda deve ser validado do seu lado.
fyrye

2
Ótimo, Atualmente, no hdparâmetro, só posso restringir um domínio, e se eu quiser restringir dois ou três domínios?
Jay Patel,

11

Lado do cliente:

Usando a auth2função init, você pode passar o hosted_domainparâmetro para restringir as contas listadas no pop-up de login às que correspondem ao seu hosted_domain. Você pode ver isso na documentação aqui: https://developers.google.com/identity/sign-in/web/reference

Lado do servidor:

Mesmo com uma lista restrita do lado do cliente, você precisará verificar se o id_tokencorresponde ao domínio hospedado que você especificou. Para algumas implementações, isso significa verificar o hdatributo que você recebe do Google após verificar o token.

Exemplo de pilha completa:

Código da web:

gapi.load('auth2', function () {
    // init auth2 with your hosted_domain
    // only matching accounts will show up in the list or be accepted
    var auth2 = gapi.auth2.init({
        client_id: "your-client-id.apps.googleusercontent.com",
        hosted_domain: 'your-special-domain.com'
    });

    // setup your signin button
    auth2.attachClickHandler(yourButtonElement, {});

    // when the current user changes
    auth2.currentUser.listen(function (user) {
        // if the user is signed in
        if (user && user.isSignedIn()) {
            // validate the token on your server,
            // your server will need to double check that the
            // `hd` matches your specified `hosted_domain`;
            validateTokenOnYourServer(user.getAuthResponse().id_token)
                .then(function () {
                    console.log('yay');
                })
                .catch(function (err) {
                    auth2.then(function() { auth2.signOut(); });
                });
        }
    });
});

Código do servidor (usando a biblioteca Googles Node.js):

Se você não usa Node.js, pode ver outros exemplos aqui: https://developers.google.com/identity/sign-in/web/backend-auth

const GoogleAuth = require('google-auth-library');
const Auth = new GoogleAuth();
const authData = JSON.parse(fs.readFileSync(your_auth_creds_json_file));
const oauth = new Auth.OAuth2(authData.web.client_id, authData.web.client_secret);

const acceptableISSs = new Set(
    ['accounts.google.com', 'https://accounts.google.com']
);

const validateToken = (token) => {
    return new Promise((resolve, reject) => {
        if (!token) {
            reject();
        }
        oauth.verifyIdToken(token, null, (err, ticket) => {
            if (err) {
                return reject(err);
            }
            const payload = ticket.getPayload();
            const tokenIsOK = payload &&
                  payload.aud === authData.web.client_id &&
                  new Date(payload.exp * 1000) > new Date() &&
                  acceptableISSs.has(payload.iss) &&
                  payload.hd === 'your-special-domain.com';
            return tokenIsOK ? resolve() : reject();
        });
    });
};

9

Ao definir seu provedor, passe um hash no final com o parâmetro 'hd'. Você pode ler sobre isso aqui. https://developers.google.com/accounts/docs/OpenIDConnect#hd-param

Por exemplo, para config / initializers / devise.rb

config.omniauth :google_oauth2, 'identifier', 'key', {hd: 'yourdomain.com'}

1
Isso pode ser facilmente contornado dando acesso ao login com outros domínios. Isso funcionará apenas para limitar as contas disponíveis mostradas ao usuário.
homaxto

2

Aqui está o que fiz usando o passaporte em node.js. profileé o usuário que está tentando fazer login.

//passed, stringified email login
var emailString = String(profile.emails[0].value);
//the domain you want to whitelist
var yourDomain = '@google.com';
//check the x amount of characters including and after @ symbol of passed user login.
//This means '@google.com' must be the final set of characters in the attempted login 
var domain = emailString.substr(emailString.length - yourDomain.length);

//I send the user back to the login screen if domain does not match 
if (domain != yourDomain)
   return done(err);

Em seguida, crie uma lógica para procurar vários domínios em vez de apenas um. Eu acredito que este método é seguro porque 1. o símbolo '@' não é um caractere válido na primeira ou segunda parte de um endereço de e-mail. Não consegui enganar a função criando um endereço de e-mail como mike@fake@google.com2. Em um sistema de login tradicional, consegui, mas esse endereço de e-mail nunca poderia existir no Google. Se não for uma conta do Google válida, você não pode fazer o login.


1

Desde 2015, existe uma função na biblioteca para definir isso sem a necessidade de editar a fonte da biblioteca como na solução alternativa de aaron-bruce

Antes de gerar o url, basta ligar setHostedDomainpara o seu cliente Google

$client->setHostedDomain("HOSTED DOMAIN")
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.