I'm using Her to speak to an API I made so that I could retrieve information from it. I need an Authorization token passed in through the headers. How would I do this? The documentation doesn't show a solution anywhere, but it seems like a very much needed utility.
#sethetter's comment basically covered it, but since I recently did something similar, I thought I would include some code, which someone might find useful in future. So, to do this, you would create a request middleware, which adds the desired headers in the call method. I had to do something similar, and the result looked like this:
class Authentication < Faraday::Middleware
def call(env)
env[:request_headers]['auth-token'] = generate_token(env)
#app.call(env)
end
def generate_token(env)
# generate the token based on the request, if needed
end
end
And then, when you construct the API stack:
require 'authentication' #if you've defined it in a different file
#api = Her::API.new
#api.setup(:url => my_api_base_url) do |c|
c.use Authentication
# other middlewares as usual
end
Related
There are similar questions like this, this, and this.
None help because the goal is to prevent logging of long parameters within a specific action instead of using config.filter_parameters. Also the answer must work for Rails 3.2.x while many answers are based on Rails 5.
One answer suggests calling request.filtered_parameters inside the controller method, but calling request.filtered_parameters.delete :long_param did not stop :long_param from getting logged.
config.filter_parameters takes a lambda function, so you can filter whatever you want. See answers here and here.
If you only want to filter long arguments for a specific action, well, you are making your life unnecessarily complicated. Either filter all long parameters, using your lambda to set a limit on parameter value length, or change the parameter key of the action you want to filter so that it is unique and and then just filter by that key.
This can be achieved with a little help from Middleware filter
Create new file app/middleware/filter_long_params.rb
class FilterLongParams
def initialize(app, long_params = [])
#app = app
#long_params = long_params
end
def call(env)
env["action_dispatch.parameter_filter"] += #long_params unless #long_params.empty?
status, headers, response = #app.call(env)
[status, headers, response]
end
end
Then add to your controller
class YourController
use FilterLongParams, [:long_param_to_be_filtered], only: :update
end
First parameter of use is the name of Middleware class, second parameter should be the array of parameters you want to be filtered, and third may be the usual scope of controller actions.
If Rails 3.2 don't autoload app/middleware path, use app/controllers instead.
I have been trying to implement the Rails API Gateway concept and I have been struggling with a way to define routes without too much of a hustle.
My current implementation looks something like this:
module ServicesEndpoints
class StackOverflow
def self.check_comment(id)
begin
RestClient.get endpoint + comment_path(id)
rescue => e
#if the server is not up or errors occur from our point of view there is no data about the driver
raise my_error
end
end
private
def self.endpoint
ENV['STACKOVERFLOW_SERVICE_ADDRESS']
end
def self.comment_path(id)
"/comments/#{id}"
end
end
end
However this means that everytime i have to add an endpoint i need 1 class and for every route 1 action. Thinking about this I was wondering if you couldn't do this in an yml/.env file and just load them. However even if I know how to put the endpoint in the .env file routes with params are a little tricky(I have no good idea on how to do it).
Has someone tackled this problem and if so how did you go about to solve it?
I'm trying to get some more information into my Rails logs, specifically the requested URI or current params, if available (and I appreciate that they won't always be). However I just don't seem able to. Here's what I've done so far:
#config/environments/production.rb
config.logger = Logger.new(config.log_path)
config.log_level = :error
config.logger.level = Logger::ERROR
#config/environment.rb
class Logger
def format_message(level, time, progname, msg)
"**********************************************************************\n#{level} #{time.to_s(:db)} -- #{msg}\n"
end
end
So I can customize the message fine, yet I don't seem to be able to access the params/request variables here. Does anyone know if this is possible, and if so how? Or if there's a better way to get this information? (Perhaps even something Redis based?)
Thanks loads,
Dan
(Responding a long time after this was asked, but maybe it will help the next person.)
I just did something similar.
1) you need to override your logger separately from logging request-leve details. Looks like you've figured customizing your logger out. Answer is here:
Rails logger format string configuration
2) I log the request and response of all requests into my service. Note, that Rails puts a tonne of stuff into the headers, so just straight dumping the request or the headers is probably a bad idea. Also of note, my application is primarily accessed via an API. If yours is primarily a web-app, as I'm guessing most people's are, you probably don't want to inspect the response.body as it will contain your html.
class ApplicationController < ActionController::Base
around_filter :global_request_logging
...
def global_request_logging
http_request_header_keys = request.headers.keys.select{|header_name| header_name.match("^HTTP.*")}
http_request_headers = request.headers.select{|header_name, header_value| http_request_header_keys.index(header_name)}
logger.info "Received #{request.method.inspect} to #{request.url.inspect} from #{request.remote_ip.inspect}. Processing with headers #{http_request_headers.inspect} and params #{params.inspect}"
begin
yield
ensure
logger.info "Responding with #{response.status.inspect} => #{response.body.inspect}"
end
end
end
This should work! :) cheers.
logger.info({:user_agent =>
request.user_agent, :remote_ip =>
request.remote_ip}.inspect)
logger.info(params.inspect)
By the by.. This should be placed in your controllers action. Ex: If you place it in your create action it should also log the user_agent i.e the browser, remote_ip i.e the remote ip of the user and all the params.
you should look in the request class
like puts request.uri.
check here for more detail http://api.rubyonrails.org/classes/ActionController/AbstractRequest.html
I need to pass a parameter from one method in a controller to another.
From my understanding I have to pass the parameters as a GET exposing it in the url string.
What is the best way to encrypt the data so no one can see what is actually getting passed in the string? Also, is there a way to pass it via POST or is my original understanding correct?
I haven't used RoR, but in the web world, this problem is solved with sessions. Using sessions you can store the parameters on the server and avoid sending sensitive data with GET or POST (both are insecure).
The Ruby on Rails Security Guide looks like a great read related to this.
I suggest you abstract your code into lib/ so that you don't have to call additional methods. Instead of making a new HTTP request, just put the code in a central place and call it from there.
class MyController < ApplicationController
def index
MyLibrary::Thing.do_stuff
end
def show
MyLibrary::Thing.do_stuff
end
end
# lib/my_library/thing.rb
module MyLibrary
module Thing
def self.do_stuff
# do stuff!
end
end
end
That way you can access the same code in multiple actions, without doing extra HTTP requests.
I've put all of my user-authentication code in one place, namely lib/auth.rb. It looks like this:
lib/auth.rb
module Admin
def do_i_have_permission_to?(permission)
# Code to check all of this goes here
end
end
I include this module as part of the application helper, so these functions are available in all the views:
application_helper.rb
require 'auth'
module ApplicationHelper
include Admin
# other stuff here
end
And I also include it as part of the application controller, so the controllers likewise can call the functions:
application.rb
require 'auth'
class ApplicationController < ActionController::Base
include Admin
end
So far, so good.
The problem is that my application is not like a normal web app. Specifically, more than one user can be logged into the system from the same computer at the same time (using the same browser). I do authentication for actions by looking at all the people who are logged in from that IP and if they can all do it, it passes.
What this means is that, if an admin wants to do something, that admin has to log everyone else out first, which is annoying. But we want the admin seal of approval on everything the admin does. So the suggestion given to me was to have it so the admin can supply a username/password combo on any page they would not normally have access to (e.g. an 'edit user' page would have these extra input fields) and the authentication routines would check for that. This means
Admin::do_i_have_permission_to?(permission)
needs to get at the current request parameters. I can't just use params[:foo] like I would in a controller, because params isn't defined; similarly request.parameters[:foo] will also not work. My searching has revealed:
The current search parameters are in the current request,
The current request is in the current controller,
The current controller is in the current dispatcher, and
I'm not sure the current dispatcher is kept anywhere.
That said, experience tells me that when I'm jumping through this many hoops, I'm very probably Doing It Wrong. So what is the right way to do it? Options I've considered are:
Just move all the functions currently in auth.rb into the ApplicationHelper where (I think) they'll have access to the request and such. Works, but clutters the hell out of the helper.
Move all the functions somewhere else they'll see those methods (I don't know where)
I'm just plain missing something.
In a typical Rails application, authentication information is stored in the active session, not the parameters. As such, it's pretty straightforward to write a helper that does what you want.
It seems rather unorthodox to create a module that is then included in ApplicationHelper. The traditional approach is to create a separate helper which in this case would probably be called AuthenticationHelper. This can then be included in any required controllers, or if you prefer, loaded into ApplicationController to make it available universally.
In general terms, Helpers should not include other Helpers. It is better to simply load multiple helpers into a given Controller.
Helper methods have full access to any instance variables declared within the controller context they are operating from. To be specific, these are instance variables only (#name) and not local variables (name). Helper methods are executed for a particular view as well.
Further, I'm not sure why a user would be providing credentials and performing an operation in the same step, at least for traditional web-based apps. Usually the process is to log in and then perform an action separately.
However, in the case of an API where each transaction is an independent operation, the most straightforward approach is to do is pull out the relevant request parameters that deal with authentication, establish some controller instance variables, and then proceed to perform the particular request given the constraints that the credentials impose.
The approach I usually follow for this sort of thing is to layer in an authentication structure in the ApplicationController itself which can perform the required checks. These are protected methods.
While it's tempting to roll in a whole heap of them such as can_edit_user? and can_create_group? these very quickly get out of hand. It is a simpler design to put in a hook for a general-purpose can_perform? or has_authority_to? method that is passed an operation and any required parameters.
For example, a very rough implementation:
class ApplicationController < ActionController::Base
protected
def has_authority_to?(operation, conditions = { })
AuthenticationCheck.send(operation, conditions)
rescue
false
end
end
module AuthenticationCheck
def self.edit_user?(conditions)
session_user == conditions[:user]
end
end
class UserController
# ...
def edit
#user = User.find(params[:id])
unless (has_authority_to?(:edit_user, :user => #user))
render(:partial => 'common/access_denied', :status => :forbidden)
end
rescue ActiveRecord::RecordNotFound
render(:partial => 'users/not_found')
end
end
Obviously you'd want to roll a lot of the authority checks into before_filter blocks to avoid repetition and to promote consistency.
A full framework example might be of more help, such as the Wristband user authentication system:
http://github.com/theworkinggroup/wristband/tree/master