15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A GoogleServiceAuthError is immutable, plain old data representing an
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// error from an attempt to authenticate with a Google service.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It could be from Google Accounts itself, or any service using Google
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Accounts (e.g expired credentials).  It may contain additional data such as
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// captcha or OTP challenges.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A GoogleServiceAuthError without additional data is just a State, defined
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// below. A case could be made to have this relation implicit, to allow raising
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// error events concisely by doing OnAuthError(GoogleServiceAuthError::NONE),
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for example. But the truth is this class is ever so slightly more than a
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// transparent wrapper around 'State' due to additional Captcha data
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (e.g consider operator=), and this would violate the style guide. Thus,
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// you must explicitly use the constructor when all you have is a State.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The good news is the implementation nests the enum inside a class, so you
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// may forward declare and typedef GoogleServiceAuthError to something shorter
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in the comfort of your own translation unit.
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef GOOGLE_APIS_GAIA_GOOGLE_SERVICE_AUTH_ERROR_H_
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define GOOGLE_APIS_GAIA_GOOGLE_SERVICE_AUTH_ERROR_H_
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DictionaryValue;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class GoogleServiceAuthError {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // These enumerations are referenced by integer value in HTML login code and
3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // in UMA histograms. Do not change the numeric values.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum State {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The user is authenticated.
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NONE = 0,
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The credentials supplied to GAIA were either invalid, or the locally
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // cached credentials have expired.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    INVALID_GAIA_CREDENTIALS = 1,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The GAIA user is not authorized to use the service.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    USER_NOT_SIGNED_UP = 2,
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Could not connect to server to verify credentials. This could be in
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // response to either failure to connect to GAIA or failure to connect to
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the service needing GAIA tokens during authentication.
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CONNECTION_FAILED = 3,
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The user needs to satisfy a CAPTCHA challenge to unlock their account.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If no other information is available, this can be resolved by visiting
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // https://accounts.google.com/DisplayUnlockCaptcha. Otherwise, captcha()
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // will provide details about the associated challenge.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CAPTCHA_REQUIRED = 4,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The user account has been deleted.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ACCOUNT_DELETED = 5,
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The user account has been disabled.
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ACCOUNT_DISABLED = 6,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The service is not available; try again later.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SERVICE_UNAVAILABLE = 7,
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The password is valid but we need two factor to get a token.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TWO_FACTOR = 8,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The requestor of the authentication step cancelled the request
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // prior to completion.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    REQUEST_CANCELED = 9,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The user has provided a HOSTED account, when this service requires
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // a GOOGLE account.
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HOSTED_NOT_ALLOWED = 10,
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Indicates the service responded to a request, but we cannot
82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // interpret the response.
83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    UNEXPECTED_SERVICE_RESPONSE = 11,
84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Indicates the service responded and response carried details of the
86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // application error.
87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    SERVICE_ERROR = 12,
88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The number of known error states.
90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    NUM_STATES = 13,
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Additional data for CAPTCHA_REQUIRED errors.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct Captcha {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Captcha();
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Captcha(const std::string& token,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            const GURL& audio,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            const GURL& img,
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            const GURL& unlock,
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            int width,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            int height);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ~Captcha();
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // For test only.
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool operator==(const Captcha &b) const;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string token;  // Globally identifies the specific CAPTCHA challenge.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GURL audio_url;     // The CAPTCHA audio to use instead of image.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GURL image_url;     // The CAPTCHA image to show the user.
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GURL unlock_url;    // Pretty unlock page containing above captcha.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int image_width;    // Width of captcha image.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int image_height;   // Height of capture image.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Additional data for TWO_FACTOR errors.
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct SecondFactor {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SecondFactor();
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SecondFactor(const std::string& token,
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 const std::string& prompt,
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 const std::string& alternate,
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 int length);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ~SecondFactor();
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // For test only.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool operator==(const SecondFactor &b) const;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Globally identifies the specific second-factor challenge.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string token;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Localised prompt text, eg Enter the verification code sent to your
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // phone number ending in XXX.
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string prompt_text;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Localized text describing an alternate option, eg Get a verification
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // code in a text message.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string alternate_text;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Character length for the challenge field.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int field_length;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For test only.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool operator==(const GoogleServiceAuthError &b) const;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Construct a GoogleServiceAuthError from a State with no additional data.
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit GoogleServiceAuthError(State s);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Construct a GoogleServiceAuthError from a network error.
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It will be created with CONNECTION_FAILED set.
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static GoogleServiceAuthError FromConnectionError(int error);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Construct a CAPTCHA_REQUIRED error with CAPTCHA challenge data from the
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the ClientLogin endpoint.
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(rogerta): once ClientLogin is no longer used, may be able to get
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // rid of this function.
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static GoogleServiceAuthError FromClientLoginCaptchaChallenge(
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::string& captcha_token,
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const GURL& captcha_image_url,
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const GURL& captcha_unlock_url);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Construct a SERVICE_ERROR error, e.g. invalid client ID, with an
157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // |error_message| which provides more information about the service error.
158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  static GoogleServiceAuthError FromServiceError(
159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      const std::string& error_message);
160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Construct an UNEXPECTED_SERVICE_RESPONSE error, with an |error_message|
162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // detailing the problems with the response.
163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  static GoogleServiceAuthError FromUnexpectedServiceResponse(
164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      const std::string& error_message);
165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Provided for convenience for clients needing to reset an instance to NONE.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (avoids err_ = GoogleServiceAuthError(GoogleServiceAuthError::NONE), due
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to explicit class and State enum relation. Note: shouldn't be inlined!
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static GoogleServiceAuthError AuthErrorNone();
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The error information.
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  State state() const;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Captcha& captcha() const;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const SecondFactor& second_factor() const;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int network_error() const;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string& token() const;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string& error_message() const;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns info about this object in a dictionary.  Caller takes
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ownership of returned dictionary.
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::DictionaryValue* ToValue() const;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns a message describing the error.
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string ToString() const;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GoogleServiceAuthError(State s, int error);
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Construct a GoogleServiceAuthError from |state| and |error_message|.
190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  GoogleServiceAuthError(State state, const std::string& error_message);
191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GoogleServiceAuthError(State s, const std::string& captcha_token,
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const GURL& captcha_audio_url,
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const GURL& captcha_image_url,
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const GURL& captcha_unlock_url,
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         int image_width,
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         int image_height);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  State state_;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Captcha captcha_;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecondFactor second_factor_;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int network_error_;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string error_message_;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // GOOGLE_APIS_GAIA_GOOGLE_SERVICE_AUTH_ERROR_H_
207