require 'soar_xt' require 'jwt' require 'securerandom' require 'time' module SoarAuthenticationToken class JwtTokenGenerator DEFAULT_CONFIGURATION = { 'expiry' => 604800 #a days worth of seconds } unless defined? DEFAULT_CONFIGURATION; DEFAULT_CONFIGURATION.freeze def initialize(configuration) @configuration = merge_with_default_configuration(configuration) validate_configuration @private_key = OpenSSL::PKey::EC.new(@configuration['private_key']) end def inject_store_provider(store_provider) @store_provider = store_provider end def generate(authenticated_identifier:, flow_identifier: nil) token_meta = generate_meta(authenticated_identifier) token = encode(token_meta) add_token_to_store(token_meta,flow_identifier) [token, token_meta] end private def generate_meta(authenticated_identifier) current_time = Time.now { 'authenticated_identifier' => authenticated_identifier, 'token_issue_time' => current_time.utc.iso8601(3), 'token_expiry_time' => (current_time + @configuration['expiry']).utc.iso8601(3), 'token_identifier' => SecureRandom.hex(32) } end def encode(meta) JWT.encode(meta, @private_key, 'ES512') end def validate_configuration raise "'private_key' must be configured" unless @configuration['private_key'] raise "'expiry' must be configured" unless @configuration['expiry'] raise "'expiry' must be an integer" unless Integer(@configuration['expiry']) end def merge_with_default_configuration(configuration) configuration = {} unless configuration Hash.deep_merge(DEFAULT_CONFIGURATION,configuration) end def add_token_to_store(meta,flow_identifier) @store_provider.add( token_identifier: meta['token_identifier'], authenticated_identifier: meta['authenticated_identifier'], token_issue_time: meta['token_issue_time'], token_expiry_time: meta['token_expiry_time'], flow_identifier: flow_identifier) end end end