Skip to content

Commit

Permalink
Added the ability to dynamically retrieve username/password from a bl…
Browse files Browse the repository at this point in the history
…ock/proc
  • Loading branch information
andyjeffries committed Apr 9, 2018
1 parent 55f99ee commit 0a78f25
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 25 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 1.6.6

Feature:

- Username and Password can now take a block/proc for dynamically retrieving the username and password, and will pass in the object if called in a current object context (thanks to Sam Starling for suggesting this lack of functionality)

## 1.6.5

Bugfix:
Expand Down
27 changes: 27 additions & 0 deletions docs/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,33 @@ class Person < Flexirest::Base
end
```

You can also pass in a Proc or a block to `username` and `password` if you want to dynamically pull it from somewhere, e.g. a [Current class descending from ActiveSupport::CurrentAttributes](http://edgeapi.rubyonrails.org/classes/ActiveSupport/CurrentAttributes.html).

```ruby
class Person < Flexirest::Base
username -> (obj) { obj ? Account.find(obj.id).username : Current.username }
password do
Rails.configuration.x.default_password
end

get :all, "/people"
get :find, "/people/:id"
end
```

In the above example, the `username` call handles things differently if it's called from an object context:

```ruby
person = Person.new(id: 1234)
person.find
```

Or if it's called from a class context:

```ruby
Person.find(id: 1234)
```

## Api-Auth

Using the [Api-Auth](https://github.com/mgomes/api_auth) integration it is very easy to sign requests. Include the Api-Auth gem in your `Gemfile` and then add it to your application. Then simply configure Api-Auth one time in your app and all requests will be signed from then on.
Expand Down
56 changes: 36 additions & 20 deletions lib/flexirest/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,30 @@ def base_url=(value)
@@base_url = value
end

def username(value = nil)
def username(value = nil, &block)
@username ||= nil
@@username ||= nil
if value.nil?
value = if @username.nil?
@@username
if block_given?
@username = block
else
@username
end
if value.nil? && superclass.respond_to?(:username)
value = superclass.username
value = if @username.nil?
@@username
else
@username
end
if value.nil? && superclass.respond_to?(:username)
value = superclass.username
end
value
end
value
else
value = CGI::escape(value) if value.present? && !value.include?("%")
@username = value
if value.respond_to?(:call)
@username = value
else
value = CGI::escape(value) if value.present? && !value.include?("%")
@username = value
end
end
end

Expand All @@ -70,20 +78,28 @@ def username=(value)
@@username = value
end

def password(value = nil)
def password(value = nil, &block)
if value.nil?
value = if @password.nil?
@@password
if block_given?
@password = block
else
@password
end
if value.nil? && superclass.respond_to?(:password)
value = superclass.password
value = if @password.nil?
@@password
else
@password
end
if value.nil? && superclass.respond_to?(:password)
value = superclass.password
end
value
end
value
else
value = CGI::escape(value) if value.present? && !value.include?("%")
@password = value
if value.respond_to?(:call)
@password = value
else
value = CGI::escape(value) if value.present? && !value.include?("%")
@password = value
end
end
end

Expand Down
16 changes: 12 additions & 4 deletions lib/flexirest/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,27 @@ def api_auth_options
end

def username
ret = nil
if object_is_class?
@object.username
ret = @object.username
ret = ret.call if ret.respond_to?(:call)
else
@object.class.username
ret = @object.class.username
ret = ret.call(@object) if ret.respond_to?(:call)
end
ret
end

def password
ret = nil
if object_is_class?
@object.password
ret = @object.password
ret = ret.call if ret.respond_to?(:call)
else
@object.class.password
ret = @object.class.password
ret = ret.call(@object) if ret.respond_to?(:call)
end
ret
end

def request_body_type
Expand Down
2 changes: 1 addition & 1 deletion lib/flexirest/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Flexirest
VERSION = "1.6.5"
VERSION = "1.6.6"
end
28 changes: 28 additions & 0 deletions spec/lib/request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,19 @@ class AuthenticatedExampleClient < Flexirest::Base
get :all, "/"
end

class AuthenticatedProcExampleClient < Flexirest::Base
base_url "http://www.example.com"
username Proc.new { |obj| obj ? "bill-#{obj.id}" : "bill" }
password do |obj|
if obj
"jones-#{obj.id}"
else
"jones"
end
end
get :all, "/"
end

class ProcDefaultExampleClient < Flexirest::Base
base_url "http://www.example.com"
get :all, "/", defaults: (Proc.new do |params|
Expand Down Expand Up @@ -167,6 +180,21 @@ class WhitelistedDateClient < Flexirest::Base
AuthenticatedExampleClient.all
end

it "should get an HTTP connection with authentication using procs when called in a class context" do
connection = double(Flexirest::Connection).as_null_object
expect(Flexirest::ConnectionManager).to receive(:get_connection).with("http://bill:jones@www.example.com").and_return(connection)
expect(connection).to receive(:get).with("/", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:'{"result":true}', response_headers:{})))
AuthenticatedProcExampleClient.all
end

it "should get an HTTP connection with authentication using procs when called in an object context" do
connection = double(Flexirest::Connection).as_null_object
expect(Flexirest::ConnectionManager).to receive(:get_connection).with("http://bill-1:jones-1@www.example.com").and_return(connection)
expect(connection).to receive(:get).with("/?id=1", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:'{"result":true}', response_headers:{})))
obj = AuthenticatedProcExampleClient.new(id: 1)
obj.all
end

it "should get an HTTP connection when called and call get on it" do
expect_any_instance_of(Flexirest::Connection).to receive(:get).with("/", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:'{"result":true}', response_headers:{})))
ExampleClient.all
Expand Down

0 comments on commit 0a78f25

Please sign in to comment.