Restreindre l'e-mail de connexion avec Google OAuth2.0 à un nom de domaine spécifique

90

Je ne parviens pas à trouver de documentation sur la façon de restreindre la connexion à mon application Web (qui utilise OAuth2.0 et les API Google) pour n'accepter que les demandes d'authentification des utilisateurs avec un e-mail sur un nom de domaine ou un ensemble de noms de domaine spécifique. Je voudrais mettre sur liste blanche plutôt que sur liste noire.

Quelqu'un a-t-il des suggestions sur la façon de procéder, de la documentation sur la méthode officiellement acceptée pour le faire ou un travail facile et sécurisé?

Pour mémoire, je ne connais aucune information sur l'utilisateur jusqu'à ce qu'il tente de se connecter via l'authentification OAuth de Google. Tout ce que je reçois en retour, ce sont les informations de base sur l'utilisateur et l'e-mail.

paradoxe870
la source
3
Je recherche cela aussi. Je possède une application que je souhaite rendre accessible uniquement aux personnes qui possèdent un compte sur notre domaine Google Apps for Business. La mise en œuvre de Google OpenID peut être plus appropriée pour nous deux ...
Aaron Bruce
1
Comment puis-je implémenter la connexion des utilisateurs de domaine à l'aide de google sdk et c #?
user1021583
1
S'il vous plaît, quelqu'un peut regarder cette question stackoverflow.com/questions/34220051/…
1
S'il vous plaît, j'ai une prime oben sur cette question, alors quelqu'un peut-il m'aider

Réponses:

42

J'ai donc une réponse pour vous. Dans la demande oauth, vous pouvez ajouter "hd = domain.com" et cela limitera l'authentification aux utilisateurs de ce domaine (je ne sais pas si vous pouvez faire plusieurs domaines). Vous pouvez trouver le paramètre hd documenté ici

J'utilise les bibliothèques google api à partir d'ici: http://code.google.com/p/google-api-php-client/wiki/OAuth2 , j'ai donc dû modifier manuellement le fichier /auth/apiOAuth2.php pour cela :

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: Je travaille toujours sur cette application et j'ai trouvé ceci, qui peut être la réponse la plus correcte à cette question. https://developers.google.com/google-apps/profiles/

Aaron Bruce
la source
Je n'étais pas au courant de ce paramètre, pouvez-vous créer un lien vers l'endroit où vous l'avez découvert?
Jason Hall
Malheureusement, j'ai dû obtenir les informations d'un de mes collègues, je n'ai trouvé cela nulle part dans la documentation de Google. Mon collègue pense qu'il a trouvé la référence dans la spécification OpenID et l'a essayé ici dans la spécification OpenAuth et cela semble fonctionner. À utiliser avec prudence, je suppose, car il semble s'agir d'une fonctionnalité non documentée.
Aaron Bruce
31
Remarque importante: même si vous spécifiez un hdparamètre dans la createAuthUrlfonction, vous devrez toujours vérifier que l'utilisateur se connecte avec l'adresse e-mail de votre domaine. Il est très facile de modifier le paramètre de lien pour autoriser toutes les adresses e-mail et ensuite accéder à votre application.
VictorKilo
1
Pour la documentation Google sur le hdvoir d'utilisation des paramètres developers.google.com/identity/work/it-apps~~V~~singular~~3rd et la référence du hdparamètre URI peut être trouvé developers.google.com/identity/protocols/... En résumé, le hdparam devrait être considéré comme un filtre d'affichage basé sur le domaine pour le côté Google Auth, mais doit toujours être validé de votre côté.
fyrye
2
Génial, actuellement, en hdparamètre, je ne peux restreindre qu'un seul domaine, que faire maintenant si je veux restreindre deux ou trois domaines?
Jay Patel
11

Côté client:

En utilisant la auth2fonction init, vous pouvez passer le hosted_domainparamètre pour restreindre les comptes répertoriés dans la fenêtre de connexion à ceux qui correspondent à votre hosted_domain. Vous pouvez le voir dans la documentation ici: https://developers.google.com/identity/sign-in/web/reference

Du côté serveur:

Même avec une liste côté client restreinte, vous devrez vérifier que le domaine id_tokencorrespond au domaine hébergé que vous avez spécifié. Pour certaines implémentations, cela signifie vérifier lehd attribut que vous recevez de Google après avoir vérifié le jeton.

Exemple de pile complète:

Code 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(); });
                });
        }
    });
});

Code du serveur (en utilisant la bibliothèque googles Node.js):

Si vous n'utilisez pas Node.js, vous pouvez voir d'autres exemples ici: 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();
        });
    });
};
Jordon Biondo
la source
9

Lors de la définition de votre fournisseur, passez un hachage à la fin avec le paramètre «hd». Vous pouvez en savoir plus ici. https://developers.google.com/accounts/docs/OpenIDConnect#hd-param

Par exemple, pour config / initializers / devise.rb

config.omniauth :google_oauth2, 'identifier', 'key', {hd: 'yourdomain.com'}
Kosmonaut
la source
1
Cela peut facilement être contourné en donnant accès à la connexion avec d'autres domaines. Cela ne fonctionnera que pour limiter les comptes disponibles affichés à l'utilisateur.
accueil au
2

Voici ce que j'ai fait en utilisant le passeport dans node.js. profileest l'utilisateur qui tente de se connecter.

//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);

Ensuite, créez simplement une logique pour rechercher plusieurs domaines au lieu d'un seul. Je pense que cette méthode est sécurisée car 1. le symbole «@» n'est pas un caractère valide dans la première ou la deuxième partie d'une adresse e-mail. Je ne pouvais pas tromper la fonction en créant une adresse e-mail comme mike@[email protected]2. Dans un système de connexion traditionnel, je pourrais, mais cette adresse e-mail ne pourrait jamais exister dans Google. S'il ne s'agit pas d'un compte Google valide, vous ne pouvez pas vous connecter.

mjoyce91
la source
1

Depuis 2015, il existe une fonction dans la bibliothèque pour définir cela sans avoir besoin de modifier la source de la bibliothèque comme dans la solution de contournement par aaron-bruce

Avant de générer l'URL, appelez simplement setHostedDomainvotre client Google

$client->setHostedDomain("HOSTED DOMAIN")
JBithell
la source