Restringir el correo electrónico de inicio de sesión con Google OAuth2.0 a un nombre de dominio específico

90

Parece que no puedo encontrar ninguna documentación sobre cómo restringir el inicio de sesión en mi aplicación web (que usa OAuth2.0 y las API de Google) para aceptar solo solicitudes de autenticación de usuarios con un correo electrónico en un nombre de dominio específico o un conjunto de nombres de dominio. Me gustaría incluirlo en la lista blanca en lugar de en la lista negra.

¿Alguien tiene alguna sugerencia sobre cómo hacer esto, documentación sobre el método oficialmente aceptado para hacerlo o una solución fácil y segura?

Para el registro, no conozco ninguna información sobre el usuario hasta que intenta iniciar sesión a través de la autenticación OAuth de Google. Todo lo que recibo es la información básica del usuario y el correo electrónico.

paradoja870
fuente
3
También estoy investigando esto. Tengo una aplicación a la que quiero que solo puedan acceder las personas que tienen una cuenta en nuestro dominio de aplicaciones de Google para empresas. La implementación de Google OpenID puede ser más apropiada para los dos ...
Aaron Bruce
1
¿Cómo puedo implementar el inicio de sesión de usuario de dominio usando google sdk y c #?
user1021583
1
Por favor, alguien puede vistazo a esta pregunta stackoverflow.com/questions/34220051/...
1
Por favor, tengo una recompensa de oben en esa pregunta, así que alguien puede ayudarme

Respuestas:

42

Así que tengo una respuesta para ti. En la solicitud de oauth puede agregar "hd = dominio.com" y restringirá la autenticación a los usuarios de ese dominio (no sé si puede hacer varios dominios). Puede encontrar el parámetro hd documentado aquí

Estoy usando las bibliotecas de google api desde aquí: http://code.google.com/p/google-api-php-client/wiki/OAuth2, así que tuve que editar manualmente el archivo /auth/apiOAuth2.php a 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";
}

Editar: todavía estoy trabajando en esta aplicación y encontré esto, que puede ser la respuesta más correcta a esta pregunta. https://developers.google.com/google-apps/profiles/

Aaron Bruce
fuente
No estaba al tanto de este parámetro, ¿puede vincularlo al lugar donde se enteró?
Jason Hall
Desafortunadamente, tuve que obtener la información de un colega mío, no encontré esto en ninguna parte de los documentos de Google. Mi compañero de trabajo cree que encontró la referencia en la especificación de OpenID y la probó aquí en la especificación de OpenAuth y parece funcionar. Use con precaución, supongo, ya que parece ser una funcionalidad no documentada.
Aaron Bruce
31
Nota importante: aunque esté especificando un hdparámetro en la createAuthUrlfunción, aún deberá verificar que el usuario esté iniciando sesión con su dirección de correo electrónico de dominio. Es muy fácil cambiar el parámetro de enlace para permitir todas las direcciones de correo electrónico y, posteriormente, obtener acceso a su aplicación.
VictorKilo
1
Para obtener la documentación de Google sobre el hduso de parámetros, consulte developers.google.com/identity/work/it-apps Y la referencia del hdparámetro URI se puede encontrar developers.google.com/identity/protocols/… En la sinopsis, el parámetro hddebe ser visto como un filtro de visualización basado en el dominio para el lado de la autenticación de Google, pero aún debe ser validado por su lado.
fyrye
2
Genial, actualmente, en el hdparámetro, solo puedo restringir un dominio. Ahora, ¿qué pasa si quiero restringir dos o tres dominios?
Jay Patel
11

Lado del cliente:

Con la auth2función init, puede pasar el hosted_domainparámetro para restringir las cuentas que aparecen en la ventana emergente de inicio de sesión a aquellas que coincidan con su hosted_domain. Puede ver esto en la documentación aquí: https://developers.google.com/identity/sign-in/web/reference

Lado del servidor:

Incluso con una lista restringida del lado del cliente, deberá verificar que id_tokencoincida con el dominio alojado que especificó. Para algunas implementaciones, esto significa verificar el hdatributo que recibe de Google después de verificar el token.

Ejemplo de pila completa:

Código 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 del servidor (usando la biblioteca Node.js de googles):

Si no está utilizando Node.js, puede ver otros ejemplos aquí: 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
fuente
9

Cuando defina su proveedor, pase un hash al final con el parámetro 'hd'. Puedes leer sobre eso aquí. https://developers.google.com/accounts/docs/OpenIDConnect#hd-param

Por ejemplo, para config / initializers / devise.rb

config.omniauth :google_oauth2, 'identifier', 'key', {hd: 'yourdomain.com'}
Kosmonaut
fuente
1
Esto puede evitarse fácilmente dando acceso para iniciar sesión con otros dominios. Solo funcionará para limitar las cuentas disponibles que se muestran al usuario.
homaxto
2

Esto es lo que hice usando passport en node.js. profilees el usuario que intenta iniciar sesión.

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

Luego, simplemente cree lógica para buscar varios dominios en lugar de solo uno. Creo que este método es seguro porque 1. el símbolo '@' no es un carácter válido en la primera o segunda parte de una dirección de correo electrónico. No pude engañar a la función creando una dirección de correo electrónico como mike@[email protected]2. En un sistema de inicio de sesión tradicional, podría, pero esta dirección de correo electrónico nunca podría existir en Google. Si no es una cuenta de Google válida, no puede iniciar sesión.

mjoyce91
fuente
1

Desde 2015 ha habido una función en la biblioteca para configurar esto sin necesidad de editar la fuente de la biblioteca como en la solución alternativa de aaron-bruce

Antes de generar la URL, simplemente llame setHostedDomaina su cliente de Google

$client->setHostedDomain("HOSTED DOMAIN")
JBithell
fuente