.. _api-auth: API Authentication ------------------ Gate One includes an authentication API that can be used when embedded into other applications. It allows the application embedding Gate One to pre-authenticate users so they won't have to re-authenticate when their browser connects to the Gate One server. Here's how it works: Enable API Authentication ^^^^^^^^^^^^^^^^^^^^^^^^^ Set ``auth = "api"`` in your server.conf: .. ansi-block:: :string_escape: \x1b[1;34m#\x1b[0m grep "^auth" server.conf auth = "api" Generate an API Key/Secret ^^^^^^^^^^^^^^^^^^^^^^^^^^ .. ansi-block:: :string_escape: \x1b[1;34m#\x1b[0m ./gateone.py --new_api_key \x1b[32m[I 120905 14:00:07 gateone:2679]\x1b[0m A new API key has been generated: NDEzMWEwYTdlZTAzNDkxMWIwMDI4YzJmZTk4YzI4OWJjM \x1b[32m[I 120905 14:00:07 gateone:2680]\x1b[0m This key can now be used to embed Gate One into other applications. .. note:: The secret is not output to the terminal to avoid it being captured in session logs. API keys and secrets are stored in your 30api_keys.conf like so:: { "*": { "gateone": { "api_keys": { "": "", "": "" } } } } You'll need to have a look at your 30api_keys.conf to see what the 'secret' is: .. ansi-block:: :string_escape: \x1b[1;34m#\x1b[0m cat settings/30api_keys.conf { "*": { "gateone": { "api_keys": { "NDEzMWEwYTdlZTAzNDkxMWIwMDI4YzJmZTk4YzI4OWJjM": "M2U5YTMxMGQ3OWNlNDJlMTg5NmY0NmUyOTk5MWYwYWFiN" } } } } In the above example our API key would be, ``"NDEzMWEwYTdlZTAzNDkxMWIwMDI4YzJmZTk4YzI4OWJjM"`` and our API secret would be, ``"M2U5YTMxMGQ3OWNlNDJlMTg5NmY0NmUyOTk5MWYwYWFiN"``. .. tip:: You can set the API Key and secret to whatever you like by editing your 30api_keys.conf. By default they're random, 45-character strings but they can be any combination of characters other than colons and commas--even `Unicode `_!. The following is a perfectly valid API key and secret: ``"ʕ•ᴥ•ʔ /人 ◕ ‿‿ ◕ 人\": "↑ ↑ ↓ ↓ ← → ← → Ⓑ Ⓐ ♥‿♥"`` Generate An Auth Object ^^^^^^^^^^^^^^^^^^^^^^^ The next step is to generate a `JSON `_ object (auth) from your application and pass it to :js:func:`GateOne.init`. The 'auth' object must contain the following information: api_key The key that was generated when you ran ``./gateone.py --new_api_key`` upn The username or userPrincipalName (aka UPN) of the user you wish to preauthenticate. timestamp A JavaScript-style timestamp: 13 digits representing the amount of milliseconds since the epoch (January 1, 1970) signature A valid `HMAC `_ signature that is generated from the api_key, upn, and timestamp (in that order). signature_method The HMAC signature method that was used to sign the authentication object. Currently, only HMAC-SHA1 is supported. api_version The version of Gate One's API authentication to use. Currently, only '1.0' is valid. Here's an example 'auth' object: .. code-block:: javascript authobj = { 'api_key': 'MjkwYzc3MDI2MjhhNGZkNDg1MjJkODgyYjBmN2MyMTM4M', 'upn': 'joe@company.com', 'timestamp': '1323391717238', 'signature': "f6c6c82281f8d56797599aeee01a5e3efab05a63", 'signature_method': 'HMAC-SHA1', 'api_version': '1.0' } This object would then be passed to :js:func:`GateOne.init` like so: .. code-block:: javascript GateOne.init({auth: authobj}) Assuming the signature is valid Gate One would then inherently trust that the user connecting over the WebSocket is joe@company.com. .. note:: Authentication objects (aka "authentication tokens") are only valid within the time frame specified in the :option:`--api_timestamp_window` setting. They also can't be used more than once (to negate replay attacks). Example API Authentication Code ------------------------------- The following are examples demonstrating how to generate valid 'auth' objects in various programming languages. Python ^^^^^^ .. code-block:: python import time, hmac, hashlib, json secret = "secret" authobj = { 'api_key': "MjkwYzc3MDI2MjhhNGZkNDg1MjJkODgyYjBmN2MyMTM4M", 'upn': "joe@company.com", 'timestamp': str(int(time.time() * 1000)), 'signature_method': 'HMAC-SHA1', 'api_version': '1.0' } hash = hmac.new(secret, digestmod=hashlib.sha1) hash.update(authobj['api_key'] + authobj['upn'] + authobj['timestamp']) authobj['signature'] = hash.hexdigest() valid_json_auth_object = json.dumps(authobj) Here's a create_signature() function that can be used as a shortcut to those hash calls above:: def create_signature(secret, *parts): import hmac, hashlib hash = hmac.new(secret, digestmod=hashlib.sha1) for part in parts: hash.update(str(part)) return hash.hexdigest() ...which could be used like so:: >>> create_signature(secret, api_key, upn, timestamp) 'f6c6c82281f8d56797599aeee01a5e3efab05a63' PHP ^^^ .. code-block:: php $secret = 'secret'; $authobj = array( 'api_key' => 'MjkwYzc3MDI2MjhhNGZkNDg1MjJkODgyYjBmN2MyMTM4M', 'upn' => $_SERVER['REMOTE_USER'], 'timestamp' => time() * 1000, 'signature_method' => 'HMAC-SHA1', 'api_version' => '1.0' ); $authobj['signature'] = hash_hmac('sha1', $authobj['api_key'] . $authobj['upn'] . $authobj['timestamp'], $secret); $valid_json_auth_object = json_encode($authobj); Ruby ^^^^ .. code-block:: ruby require 'cgi' require 'openssl' require 'json' secret = 'secret' authobj = { 'api_key' => 'MjkwYzc3MDI2MjhhNGZkNDg1MjJkODgyYjBmN2MyMTM4M', 'upn' => 'joe@company.com', 'timestamp' => (Time.now.getutc.to_i * 1000).inspect, 'signature_method' => 'HMAC-SHA1', 'api_version' => '1.0' } authobj['signature' = OpenSSL::HMAC.hexdigest('sha1', secret, authobj['api_key'] + authobj['upn'] + authobj['timestamp']) valid_json_auth_object = JSON.generate(authobj)