| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef REMOTING_PROTOCOL_NEGOTIATING_AUTHENTICATOR_BASE_H_ | 
 | #define REMOTING_PROTOCOL_NEGOTIATING_AUTHENTICATOR_BASE_H_ | 
 |  | 
 | #include <memory> | 
 | #include <string> | 
 | #include <vector> | 
 |  | 
 | #include "base/gtest_prod_util.h" | 
 | #include "base/macros.h" | 
 | #include "base/memory/ref_counted.h" | 
 | #include "remoting/protocol/authenticator.h" | 
 |  | 
 | namespace buzz { | 
 | struct StaticQName; | 
 | }  // namespace buzz | 
 |  | 
 | namespace remoting { | 
 | namespace protocol { | 
 |  | 
 | // This class provides the common base for a meta-authenticator that allows | 
 | // clients and hosts that support multiple authentication methods to negotiate a | 
 | // method to use. | 
 | // | 
 | // The typical flow is: | 
 | //  * Client sends a message to host with its supported methods. | 
 | //      (clients may additionally pick a method and send its first message). | 
 | //  * Host picks a method and sends its first message (if any). | 
 | //      (if a message for that method was sent by the client, it is processed). | 
 | //  * Client creates the authenticator selected by the host. If the method | 
 | //      starts with a message from the host, it is processed. | 
 | //  * Client and host exchange messages until the authentication is ACCEPTED or | 
 | //      REJECTED. | 
 | // | 
 | // The details: | 
 | //  * CreateAuthenticator() may be asynchronous (i.e. require user interaction | 
 | //      to determine initial parameters, like PIN). This happens inside | 
 | //      ProcessMessage, so to the outside this behaves like any asynchronous | 
 | //      message processing. Internally, CreateAuthenticator() receives a | 
 | //      callback, that will resume the authentication once the authenticator is | 
 | //      created. If there is already a message to be processed by the new | 
 | //      authenticator, this callback includes a call to the underlying | 
 | //      ProcessMessage(). | 
 | //  * Some authentication methods may have a specific starting direction (e.g. | 
 | //      host always sends the first message), while others are versatile (e.g. | 
 | //      SPAKE, where either side can send the first message). When an | 
 | //      authenticator is created, it is given a preferred initial state, which | 
 | //      the authenticator may ignore. | 
 | //  * If the new authenticator state doesn't match the preferred one, | 
 | //      the NegotiatingAuthenticator deals with that, by sending an empty | 
 | //      <authenticator> stanza if the method has no message to send, and | 
 | //      ignoring such empty messages on the receiving end. | 
 | //  * The client may optimistically pick a method on its first message (assuming | 
 | //      it doesn't require user interaction to start). If the host doesn't | 
 | //      support that method, it will just discard that message, and choose | 
 | //      another method from the client's supported methods list. | 
 | //  * The host never sends its own supported methods back to the client, so once | 
 | //      the host picks a method from the client's list, it's final. | 
 | //  * Any change in this class must maintain compatibility between any version | 
 | //      mix of webapp, client plugin and host, for both Me2Me and IT2Me. | 
 | class NegotiatingAuthenticatorBase : public Authenticator { | 
 |  public: | 
 |   // Method represents an authentication algorithm. | 
 |   enum class Method { | 
 |     INVALID, | 
 |  | 
 |     // SPAKE2 with P224 using access code in plain-text. Used for It2Me. | 
 |     // TODO(sergeyu): Remove and use SHARED_SECRET_SPAKE2_CURVE25519 once | 
 |     // the population of M50 hosts (which require this for IT2Me) is | 
 |     // sufficiently low: crbug.com/607643. | 
 |     SHARED_SECRET_PLAIN_SPAKE2_P224, | 
 |  | 
 |     // SPAKE2 PIN or access code hashed with host_id using HMAC-SHA256. | 
 |     SHARED_SECRET_SPAKE2_P224, | 
 |     SHARED_SECRET_SPAKE2_CURVE25519, | 
 |  | 
 |     // SPAKE2 using shared pairing secret. Falls back to PIN-based | 
 |     // authentication when pairing fails. | 
 |     PAIRED_SPAKE2_P224, | 
 |     PAIRED_SPAKE2_CURVE25519, | 
 |  | 
 |     // Authentication using third-party authentication server. | 
 |     // SPAKE2 with P224 using shared pairing secret. Falls back to PIN-based | 
 |     // authentication when it fails to authenticate using paired secret. | 
 |     THIRD_PARTY_SPAKE2_P224, | 
 |     THIRD_PARTY_SPAKE2_CURVE25519, | 
 |   }; | 
 |  | 
 |   ~NegotiatingAuthenticatorBase() override; | 
 |  | 
 |   // Authenticator interface. | 
 |   State state() const override; | 
 |   bool started() const override; | 
 |   RejectionReason rejection_reason() const override; | 
 |   const std::string& GetAuthKey() const override; | 
 |   std::unique_ptr<ChannelAuthenticator> CreateChannelAuthenticator() | 
 |       const override; | 
 |  | 
 |   // Calls |current_authenticator_| to process |message|, passing the supplied | 
 |   // |resume_callback|. | 
 |   void ProcessMessageInternal(const buzz::XmlElement* message, | 
 |                               const base::Closure& resume_callback); | 
 |  | 
 |  protected: | 
 |   friend class NegotiatingAuthenticatorTest; | 
 |  | 
 |   static const buzz::StaticQName kMethodAttributeQName; | 
 |   static const buzz::StaticQName kSupportedMethodsAttributeQName; | 
 |   static const char kSupportedMethodsSeparator; | 
 |  | 
 |   static const buzz::StaticQName kPairingInfoTag; | 
 |   static const buzz::StaticQName kClientIdAttribute; | 
 |  | 
 |   // Parses a string that defines an authentication method. Returns | 
 |   // Method::INVALID if the string is invalid. | 
 |   static Method ParseMethodString(const std::string& value); | 
 |  | 
 |   // Returns string representation of |method|. | 
 |   static std::string MethodToString(Method method); | 
 |  | 
 |   explicit NegotiatingAuthenticatorBase(Authenticator::State initial_state); | 
 |  | 
 |   void AddMethod(Method method); | 
 |  | 
 |   // Updates |state_| to reflect the current underlying authenticator state. | 
 |   // |resume_callback| is called after the state is updated. | 
 |   void UpdateState(const base::Closure& resume_callback); | 
 |  | 
 |   // Gets the next message from |current_authenticator_|, if any, and fills in | 
 |   // the 'method' tag with |current_method_|. | 
 |   virtual std::unique_ptr<buzz::XmlElement> GetNextMessageInternal(); | 
 |  | 
 |   std::vector<Method> methods_; | 
 |   Method current_method_ = Method::INVALID; | 
 |   std::unique_ptr<Authenticator> current_authenticator_; | 
 |   State state_; | 
 |   RejectionReason rejection_reason_ = INVALID_CREDENTIALS; | 
 |  | 
 |  private: | 
 |   DISALLOW_COPY_AND_ASSIGN(NegotiatingAuthenticatorBase); | 
 | }; | 
 |  | 
 | }  // namespace protocol | 
 | }  // namespace remoting | 
 |  | 
 | #endif  // REMOTING_PROTOCOL_NEGOTIATING_AUTHENTICATOR_BASE_H_ |