Ogranicz adres e-mail logowania za pomocą Google OAuth2.0 do określonej nazwy domeny

90

Nie mogę znaleźć żadnej dokumentacji na temat tego, jak ograniczyć logowanie do mojej aplikacji internetowej (która korzysta z OAuth2.0 i interfejsów API Google), aby akceptować tylko żądania uwierzytelnienia od użytkowników z adresem e-mail w określonej nazwie domeny lub zestawie nazw domen. Chciałbym umieścić na białej liście, a nie na czarnej liście.

Czy ktoś ma sugestie, jak to zrobić, dokumentację na temat oficjalnie przyjętej metody lub łatwe, bezpieczne obejście?

Dla przypomnienia, nie znam żadnych informacji o użytkowniku, dopóki nie spróbuje zalogować się za pomocą uwierzytelniania OAuth firmy Google. Otrzymuję tylko podstawowe informacje o użytkowniku i e-mail.

paradox870
źródło
3
Ja też to badam. Mam aplikację, do której chcę mieć dostęp tylko dla osób posiadających konto w naszych aplikacjach Google dla domeny biznesowej. Implementacja Google OpenID może być bardziej odpowiednia dla nas obojga ...
Aaron Bruce,
1
Jak mogę zaimplementować logowanie użytkowników domeny przy użyciu Google SDK i C #?
user1021583
1
Czy ktoś może spojrzeć na to pytanie stackoverflow.com/questions/34220051/ ...
1
Proszę, mam nagrodę oben za to pytanie, więc ktoś może mi pomóc

Odpowiedzi:

42

Więc mam dla ciebie odpowiedź. W żądaniu oauth możesz dodać „hd = domain.com” i ograniczy to uwierzytelnianie do użytkowników z tej domeny (nie wiem, czy możesz zrobić wiele domen). Możesz znaleźć udokumentowany parametr hd tutaj

Używam bibliotek Google API stąd: http://code.google.com/p/google-api-php-client/wiki/OAuth2, więc musiałem ręcznie edytować plik /auth/apiOAuth2.php do tego :

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";
}

Edycja: wciąż pracuję nad tą aplikacją i znalazłem to, co może być bardziej poprawną odpowiedzią na to pytanie. https://developers.google.com/google-apps/profiles/

Aaron Bruce
źródło
Nie byłem świadomy tego parametru, czy możesz podać link do miejsca, w którym się o nim dowiedziałeś?
Jason Hall
Niestety musiałem uzyskać informacje od mojego kolegi, nie znalazłem tego nigdzie w dokumentach Google. Mój współpracownik uważa, że ​​znalazł odniesienie w specyfikacji OpenID i wypróbował je tutaj w specyfikacji OpenAuth i wydaje się, że działa. Używaj ostrożnie, jak sądzę, ponieważ wydaje się, że jest to nieudokumentowana funkcjonalność.
Aaron Bruce
31
Ważna uwaga: nawet jeśli określasz hdparametr w createAuthUrlfunkcji, nadal będziesz musiał sprawdzić, czy użytkownik loguje się przy użyciu adresu e-mail Twojej domeny. Bardzo łatwo jest zmienić parametr łącza, aby zezwolić na wszystkie adresy e-mail, a następnie uzyskać dostęp do aplikacji.
VictorKilo,
1
Dokumentacja Google dotycząca hdużycia parametrów znajduje się na developers.google.com/identity/work/it-apps . Odniesienie do hdparametru URI można znaleźć developers.google.com/identity/protocols/… W skrócie hdparametr powinien być jest postrzegany jako filtr wyświetlania oparty na domenie po stronie Google Auth, ale nadal powinien zostać zweryfikowany po Twojej stronie.
Will B.
2
Świetnie, obecnie w hdparametrze mogę ograniczyć tylko jedną domenę, a co jeśli chcę ograniczyć dwie lub trzy domeny?
Jay Patel
11

Strona klienta:

Korzystając z auth2funkcji init, możesz przekazać hosted_domainparametr, aby ograniczyć konta wymienione w wyskakującym okienku logowania do tych, które pasują do Twojego hosted_domain. Możesz to zobaczyć w dokumentacji tutaj: https://developers.google.com/identity/sign-in/web/reference

Po stronie serwera:

Nawet w przypadku ograniczonej listy po stronie klienta musisz sprawdzić, czy id_tokenpasuje do określonej domeny hostowanej. W przypadku niektórych implementacji oznacza to sprawdzenie hdatrybutu, który otrzymujesz od Google po zweryfikowaniu tokena.

Przykład pełnego stosu:

Kod sieciowy:

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

Kod serwera (przy użyciu biblioteki googles Node.js):

Jeśli nie używasz Node.js, możesz zobaczyć inne przykłady tutaj: 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
źródło
9

Definiując swojego dostawcę, podaj skrót na końcu z parametrem „hd”. Możesz o tym przeczytać tutaj. https://developers.google.com/accounts/docs/OpenIDConnect#hd-param

Np. Dla config / initializers / devise.rb

config.omniauth :google_oauth2, 'identifier', 'key', {hd: 'yourdomain.com'}
Kosmonaut
źródło
1
Można to łatwo obejść, dając dostęp do logowania w innych domenach. Będzie działać tylko w celu ograniczenia dostępnych kont wyświetlanych użytkownikowi.
homaxto
2

Oto, co zrobiłem, używając paszportu w node.js. profileto użytkownik próbujący się zalogować.

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

Następnie stwórz logikę, aby szukać wielu domen zamiast tylko jednej. Uważam, że ta metoda jest bezpieczna, ponieważ 1. symbol „@” nie jest prawidłowym znakiem w pierwszej lub drugiej części adresu e-mail. Nie mogłem oszukać funkcji, tworząc adres e-mail taki jak mike@[email protected]2. W tradycyjnym systemie logowania mogłem, ale ten adres e-mail nigdy nie mógł istnieć w Google. Jeśli nie jest to prawidłowe konto Google, nie możesz się zalogować.

mjoyce91
źródło
1

Od 2015 roku w bibliotece istnieje funkcja umożliwiająca ustawienie tego bez konieczności edytowania źródła biblioteki, tak jak w obejściu przez aarona-bruce'a

Przed wygenerowaniem adresu URL po prostu zadzwoń setHostedDomaindo swojego klienta Google

$client->setHostedDomain("HOSTED DOMAIN")
JBithell
źródło