include/pulsar/Authentication.h (162 lines of code) (raw):

/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef PULSAR_AUTHENTICATION_H_ #define PULSAR_AUTHENTICATION_H_ #include <pulsar/Result.h> #include <pulsar/defines.h> #include <functional> #include <map> #include <memory> #include <string> #include <vector> namespace pulsar { class ClientConfiguration; class Authentication; class PULSAR_PUBLIC AuthenticationDataProvider { public: virtual ~AuthenticationDataProvider(); /** * @return true if the authentication data contains data for TLS */ virtual bool hasDataForTls(); /** * @return a client certificate chain or “none” if the data is not available */ virtual std::string getTlsCertificates(); /** * @return a private key for the client certificate or “none” if the data is not available */ virtual std::string getTlsPrivateKey(); /** * @return true if this authentication data contains data for HTTP */ virtual bool hasDataForHttp(); /** * @return an authentication scheme or “none” if the request is not authenticated */ virtual std::string getHttpAuthType(); /** * @return the string of HTTP header or “none” if the request is not authenticated */ virtual std::string getHttpHeaders(); /** * @return true if authentication data contains data from Pulsar protocol */ virtual bool hasDataFromCommand(); /** * @return authentication data which is stored in a command */ virtual std::string getCommandData(); protected: AuthenticationDataProvider(); }; typedef std::shared_ptr<AuthenticationDataProvider> AuthenticationDataPtr; typedef std::shared_ptr<Authentication> AuthenticationPtr; typedef std::map<std::string, std::string> ParamMap; class PULSAR_PUBLIC Authentication { public: virtual ~Authentication(); /** * @return the authentication method name supported by this provider */ virtual const std::string getAuthMethodName() const = 0; /** * Get AuthenticationData from the current instance * * @param[out] authDataContent the shared pointer of AuthenticationData. The content of AuthenticationData * is changed to the internal data of the current instance. * @return ResultOk or ResultAuthenticationError if authentication failed */ virtual Result getAuthData(AuthenticationDataPtr& authDataContent) { authDataContent = authData_; return ResultOk; } /** * Parse the authentication parameter string to a map whose key and value are both strings * * The parameter string can have multiple lines. The format of each line is a comma-separated “key:value” * string. * * For example, “k1:v1,k2:v2” is parsed to two key-value pairs `(k1, v1)` and `(k2, v2)`. * * @param authParamsString the authentication parameter string to be parsed * @return the parsed map whose key and value are both strings */ static ParamMap parseDefaultFormatAuthParams(const std::string& authParamsString); protected: Authentication(); AuthenticationDataPtr authData_; friend class ClientConfiguration; }; /** * AuthFactory is used to create instances of Authentication class when * configuring a Client instance. It loads the authentication from an * external plugin. * * To use authentication methods that are internally supported, you should * use `AuthTls::create("my-cert.pem", "my-private.key")` or similar. */ class PULSAR_PUBLIC AuthFactory { public: static AuthenticationPtr Disabled(); /** * Create an AuthenticationPtr with an empty ParamMap * * @see create(const std::string&, const ParamMap&) */ static AuthenticationPtr create(const std::string& pluginNameOrDynamicLibPath); /** * Create an AuthenticationPtr with a ParamMap that is converted from authParamsString * * @see Authentication::parseDefaultFormatAuthParams * @see create(const std::string&, const ParamMap&) */ static AuthenticationPtr create(const std::string& pluginNameOrDynamicLibPath, const std::string& authParamsString); /** * Create an AuthenticationPtr * * When the first parameter represents the plugin name, the type of authentication can be one of the * following: * - AuthTls (if the plugin name is “tls”) * - AuthToken (if the plugin name is “token” or “org.apache.pulsar.client.impl.auth.AuthenticationToken”) * - AuthAthenz (if the plugin name is “athenz” or * “org.apache.pulsar.client.impl.auth.AuthenticationAthenz”) * - AuthOauth2 (if the plugin name is “oauth2token” or * “org.apache.pulsar.client.impl.auth.oauth2.AuthenticationOAuth2”) * * @param pluginNameOrDynamicLibPath the plugin name or the path or a dynamic library that contains the * implementation of Authentication * @param params the ParamMap that is passed to Authentication::create method */ static AuthenticationPtr create(const std::string& pluginNameOrDynamicLibPath, ParamMap& params); protected: static bool isShutdownHookRegistered_; static std::vector<void*> loadedLibrariesHandles_; static void release_handles(); }; /** * TLS implementation of Pulsar client authentication */ class PULSAR_PUBLIC AuthTls : public Authentication { public: AuthTls(AuthenticationDataPtr&); ~AuthTls(); /** * Create an AuthTls with a ParamMap * * It is equal to create(params[“tlsCertFile”], params[“tlsKeyFile”]) * @see create(const std::string&, const std::string&) */ static AuthenticationPtr create(ParamMap& params); /** * Create an AuthTls with an authentication parameter string * * @see Authentication::parseDefaultFormatAuthParams */ static AuthenticationPtr create(const std::string& authParamsString); /** * Create an AuthTls with the required parameters * * @param certificatePath the file path for a client certificate * @param privateKeyPath the file path for a client private key */ static AuthenticationPtr create(const std::string& certificatePath, const std::string& privateKeyPath); /** * @return “tls” */ const std::string getAuthMethodName() const; /** * Get AuthenticationData from the current instance * * @param[out] authDataTls the shared pointer of AuthenticationData. The content of AuthenticationData is * changed to the internal data of the current instance. * @return ResultOk */ Result getAuthData(AuthenticationDataPtr& authDataTls); private: AuthenticationDataPtr authDataTls_; }; typedef std::function<std::string()> TokenSupplier; /** * Token based implementation of Pulsar client authentication */ class PULSAR_PUBLIC AuthToken : public Authentication { public: AuthToken(AuthenticationDataPtr&); ~AuthToken(); /** * Create an AuthToken with a ParamMap * * @param parameters it must contain a key-value, where key means how to get the token and value means the * token source * * If the key is “token”, the value is the token * * If the key is “file”, the value is the file that contains the token * * If the key is “env”, the value is the environment variable whose value is the token * * Otherwise, a `std::runtime_error` error is thrown. * @see create(const std::string& authParamsString) */ static AuthenticationPtr create(ParamMap& params); /** * Create an AuthToken with an authentication parameter string * * @see Authentication::parseDefaultFormatAuthParams */ static AuthenticationPtr create(const std::string& authParamsString); /** * Create an authentication provider for token based authentication * * @param token * a string containing the auth token */ static AuthenticationPtr createWithToken(const std::string& token); /** * Create an authentication provider for token based authentication * * @param tokenSupplier * a supplier of the client auth token */ static AuthenticationPtr create(const TokenSupplier& tokenSupplier); /** * @return “token” */ const std::string getAuthMethodName() const; /** * Get AuthenticationData from the current instance * * @param[out] authDataToken the shared pointer of AuthenticationData. The content of AuthenticationData * is changed to the internal data of the current instance. * @return ResultOk */ Result getAuthData(AuthenticationDataPtr& authDataToken); private: AuthenticationDataPtr authDataToken_; }; /** * Basic based implementation of Pulsar client authentication */ class PULSAR_PUBLIC AuthBasic : public Authentication { public: explicit AuthBasic(AuthenticationDataPtr&); ~AuthBasic() override; /** * Create an AuthBasic with a ParamMap * * It is equal to create(params[“username”], params[“password”]) * @see create(const std::string&, const std::string&) */ static AuthenticationPtr create(ParamMap& params); /** * Create an AuthBasic with an authentication parameter string * * @param authParamsString the JSON format string: {"username": "admin", "password": "123456"} */ static AuthenticationPtr create(const std::string& authParamsString); /** * Create an AuthBasic with the required parameters */ static AuthenticationPtr create(const std::string& username, const std::string& password); /** * Create an AuthBasic with the required parameters */ static AuthenticationPtr create(const std::string& username, const std::string& password, const std::string& method); /** * @return “basic” */ const std::string getAuthMethodName() const override; /** * Get AuthenticationData from the current instance * * @param[out] authDataBasic the shared pointer of AuthenticationData. The content of AuthenticationData * is changed to the internal data of the current instance. * @return ResultOk */ Result getAuthData(AuthenticationDataPtr& authDataBasic) override; private: AuthenticationDataPtr authDataBasic_; }; /** * Athenz implementation of Pulsar client authentication */ class PULSAR_PUBLIC AuthAthenz : public Authentication { public: AuthAthenz(AuthenticationDataPtr&); ~AuthAthenz(); /** * Create an AuthAthenz with a ParamMap * * The required parameter keys are “tenantDomain”, “tenantService”, “providerDomain”, “privateKey”, and * “ztsUrl” * * @param params the key-value to construct ZTS client * @see http://pulsar.apache.org/docs/en/security-athenz/ */ static AuthenticationPtr create(ParamMap& params); /** * Create an AuthAthenz with an authentication parameter string * * @see Authentication::parseDefaultFormatAuthParams */ static AuthenticationPtr create(const std::string& authParamsString); /** * @return “athenz” */ const std::string getAuthMethodName() const; /** * Get AuthenticationData from the current instance * * @param[out] authDataAthenz the shared pointer of AuthenticationData. The content of AuthenticationData * is changed to the internal data of the current instance. * @return ResultOk */ Result getAuthData(AuthenticationDataPtr& authDataAthenz); private: AuthenticationDataPtr authDataAthenz_; }; // OAuth 2.0 token and associated information. // currently mainly works for access token class Oauth2TokenResult { public: enum { undefined_expiration = -1 }; Oauth2TokenResult(); ~Oauth2TokenResult(); /** * Set the access token string * * @param accessToken the access token string */ Oauth2TokenResult& setAccessToken(const std::string& accessToken); /** * Set the ID token * * @param idToken the ID token */ Oauth2TokenResult& setIdToken(const std::string& idToken); /** * Set the refresh token which can be used to obtain new access tokens using the same authorization grant * or null for none * * @param refreshToken the refresh token */ Oauth2TokenResult& setRefreshToken(const std::string& refreshToken); /** * Set the token lifetime * * @param expiresIn the token lifetime */ Oauth2TokenResult& setExpiresIn(const int64_t expiresIn); /** * @return the access token string */ const std::string& getAccessToken() const; /** * @return the ID token */ const std::string& getIdToken() const; /** * @return the refresh token which can be used to obtain new access tokens using the same authorization * grant or null for none */ const std::string& getRefreshToken() const; /** * @return the token lifetime in milliseconds */ int64_t getExpiresIn() const; private: // map to json "access_token" std::string accessToken_; // map to json "id_token" std::string idToken_; // map to json "refresh_token" std::string refreshToken_; // map to json "expires_in" int64_t expiresIn_; }; typedef std::shared_ptr<Oauth2TokenResult> Oauth2TokenResultPtr; class Oauth2Flow { public: virtual ~Oauth2Flow(); /** * Initializes the authorization flow. */ virtual void initialize() = 0; /** * Acquires an access token from the OAuth 2.0 authorization server. * @return a token result including an access token. */ virtual Oauth2TokenResultPtr authenticate() = 0; /** * Closes the authorization flow. */ virtual void close() = 0; protected: Oauth2Flow(); }; typedef std::shared_ptr<Oauth2Flow> FlowPtr; class CachedToken { public: virtual ~CachedToken(); /** * @return true if the token has expired */ virtual bool isExpired() = 0; /** * Get AuthenticationData from the current instance * * @return ResultOk or ResultAuthenticationError if authentication failed */ virtual AuthenticationDataPtr getAuthData() = 0; protected: CachedToken(); }; typedef std::shared_ptr<CachedToken> CachedTokenPtr; /** * Oauth2 based implementation of Pulsar client authentication. * Passed in parameter would be like: * ``` * "type": "client_credentials", * "issuer_url": "https://accounts.google.com", * "client_id": "d9ZyX97q1ef8Cr81WHVC4hFQ64vSlDK3", * "client_secret": "on1uJ...k6F6R", * "audience": "https://broker.example.com" * ``` * If passed in as std::string, it should be in Json format. */ class PULSAR_PUBLIC AuthOauth2 : public Authentication { public: AuthOauth2(ParamMap& params); ~AuthOauth2(); /** * Create an AuthOauth2 with a ParamMap * * The required parameter keys are “issuer_url”, “private_key”, and “audience” * * @param parameters the key-value to create OAuth 2.0 client credentials * @see http://pulsar.apache.org/docs/en/security-oauth2/#client-credentials */ static AuthenticationPtr create(ParamMap& params); /** * Create an AuthOauth2 with an authentication parameter string * * @see Authentication::parseDefaultFormatAuthParams */ static AuthenticationPtr create(const std::string& authParamsString); /** * @return “token” */ const std::string getAuthMethodName() const; /** * Get AuthenticationData from the current instance * * @param[out] authDataOauth2 the shared pointer of AuthenticationData. The content of AuthenticationData * is changed to the internal data of the current instance. * @return ResultOk or ResultAuthenticationError if authentication failed */ Result getAuthData(AuthenticationDataPtr& authDataOauth2); private: FlowPtr flowPtr_; CachedTokenPtr cachedTokenPtr_; }; } // namespace pulsar #endif /* PULSAR_AUTHENTICATION_H_ */