cyberark/conjur-api-ruby

View on GitHub
lib/conjur/api/authn.rb

Summary

Maintainability
A
0 mins
Test Coverage
B
81%
#
# Copyright 2013-2017 Conjur Inc
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
require 'conjur/user'

module Conjur
  class API
    def whoami
      JSON.parse(url_for(:whoami, credentials).get)
    end

    class << self
      #@!group Authentication

      # Exchanges a username and a password for an api key.  The api key
      #   is preferable for storage and use in code, as it can be rotated and has far greater entropy than
      #   a user memorizable password.
      #
      #  * Note that this method works only for {Conjur::User}s. While
      #   {Conjur::Host}s are roles, they do not have passwords.
      #  * If you pass an api key to this method instead of a password, it will verify and return the API key.
      #  * This method uses HTTP Basic Authentication to send the credentials.
      #
      # @example
      #   bob_api_key = Conjur::API.login('bob', 'bob_password')
      #   bob_api_key == Conjur::API.login('bob', bob_api_key)  # => true
      #
      # @param [String] username The `username` or `login` for the
      #   {http://developer.conjur.net/reference/services/directory/user Conjur User}.
      # @param [String] password The `password` or `api key` to authenticate with.
      # @param [String] account The organization account.
      # @return [String] the API key.
      def login username, password, account: Conjur.configuration.account
        if Conjur.log
          Conjur.log << "Logging in #{username} to account #{account} via Basic authentication\n"
        end
        url_for(:authn_login, account, username, password).get
      end

      # Authenticates using a third party authenticator like authn-oidc.  It will return an
      # access token to be used to authenticate further API calls.
      #
      # @param [String] authenticator
      # @param [String] service_id
      # @param [String] account The organization account.
      # @param [Hash] params Additional params to send to authenticator
      # @return [String] A JSON formatted authentication token.
      def authenticator_authenticate authenticator, service_id, account: Conjur.configuration.account, options: {}
        JSON.parse authenticator_authenticate_get authenticator, service_id, account: account, options: options
      end

      # Authenticates using a third party authenticator like authn-oidc via GET request.
      # It will return an response object containing access/refresh token data.
      #
      # @param [String] authenticator
      # @param [String] service_id
      # @param [String] account The organization account.
      # @param [Hash] params Additional params to send to authenticator
      # @return [RestClient::Response] Response object
      def authenticator_authenticate_get authenticator, service_id, account: Conjur.configuration.account, options: {}
        if Conjur.log
          Conjur.log << "Authenticating to account #{account} using #{authenticator}/#{service_id}\n"
        end
        url_for(:authenticator_authenticate, account, service_id, authenticator, options).get
      end

      # Exchanges Conjur the API key (refresh token) for an access token.  The access token can
      # then be used to authenticate further API calls.
      #
      # @param [String] username The username or host id for which we want a token
      # @param [String] api_key The api key
      # @param [String] account The organization account.
      # @return [String] A JSON formatted authentication token.
      def authenticate username, api_key, account: Conjur.configuration.account
        account ||= Conjur.configuration.account
        if Conjur.log
          Conjur.log << "Authenticating #{username} to account #{account}\n"
        end
        JSON.parse url_for(:authn_authenticate, account, username).post(api_key, content_type: 'text/plain')
      end

      # Obtains an access token from the +authn_local+ service. The access token can
      # then be used to authenticate further API calls.
      #
      # @param [String] username The username or host id for which we want a token
      # @param [String] account The organization account.
      # @return [String] A JSON formatted authentication token.
      def authenticate_local username, account: Conjur.configuration.account, expiration: nil, cidr: nil
        account ||= Conjur.configuration.account
        if Conjur.log
          Conjur.log << "Authenticating #{username} to account #{account} using authn_local\n"
        end

        require 'json'
        require 'socket'
        message = url_for(:authn_authenticate_local, username, account, expiration, cidr)
        JSON.parse(UNIXSocket.open(Conjur.configuration.authn_local_socket) {|s| s.puts message; s.gets })
      end

      # Change a user's password.  To do this, you must have the user's current password.  This does not change or rotate
      #   api keys. However, you *can* use the user's api key as the *current* password, if the user was not created
      #   with a password.
      #
      # @param [String] username the name of the user whose password we want to change.
      # @param [String] password the user's *current* password *or* api key.
      # @param [String] new_password the new password for the user.
      # @param [String] account The organization account.
      # @return [void]
      def update_password username, password, new_password, account: Conjur.configuration.account
        if Conjur.log
          Conjur.log << "Updating password for #{username} in account #{account}\n"
        end
        url_for(:authn_update_password, account, username, password).put new_password
      end

      #@!endgroup

      #@!group Password and API key management

      # Rotate the currently authenticated user or host API key by generating and returning a new one.
      # The old API key is no longer valid after calling this method.  You must have the current
      # API key or password to perform this operation.  This method *does not* affect a user's password.
      #
      # @param [String] username the name of the user or host whose API key we want to change
      # @param [String] password the user's current api key
      # @param [String] account The organization account.
      # @return [String] the new API key
      def rotate_api_key username, password, account: Conjur.configuration.account
        if Conjur.log
          Conjur.log << "Rotating API key for self (#{username} in account #{account})\n"
        end

        url_for(:authn_rotate_own_api_key, account, username, password).put('').body
      end

      #@!endgroup
    end
  end
end