Any way to debug RSpec request specs? - ruby-on-rails

I am writing a test for a Rails API in RSpec and the endpoint has token authentication set up. I need to pass an Authorization header in the request, but I keep getting a 401 unauthorized error. Is there any way to debug and get some insight into actually which headers are being passed etc. from these types of specs? Otherwise it seems like shooting in the dark. I should note that the token provided below is working perfectly in Postman.
describe "Chirps API" do
it "GET /chirps should return 200" do
get "/chirps", headers: {
"Authorization": "Token token=7cc9f851ea0e4013b7b15ec9131f6d58"
}
expect(response).to have_http_status(200)
end
end

Assuming your controller action is chirps as well, this will help you see the complete request object
def chirps
Rails.logger.info(request.env) # complete request object
Rails.logger.info(request.headers) #just the headers
...
end

To be more interactive you can insert a byebug, then issue the command.
it { byebug }
Then enter your get in the console.

Related

How do i test requests with digest authentication on RSpec

Hope you're having a great day.
I'm new to security in Rails and I've come through a problem of authenticating a Digest request on tests in Rails. From the course I'm learning this from (which doesn't use tests), the Digest authentication provided by Rails is not really that much used, so there wouldn't be a necessity for it. But i still got curious on how to test it with RSpec, which led me to a lot of hours trying to do something that probably isn't supposed to be done.
Anyways, here's my dilemma, it seems to me that a Digest authentication needs two requests, where it can send some variables through the header (like "nonce" and "opaque") and another that receives some calculated stuff with the "failed" request header (like "cnonce" and "response").
Bellow is a code of a helper to make the second header before mocking the request again, which would then make a OK status. Unfortunately, there're some variables lacking (in the case, "cnonce" and "response"), and i have no idea where to find them. I tried finding methods in Digest related classes on Ruby and Rails, but none seem to make these calculations, although i feel like i'm not seeing something here.
class DigestHeaderWriter
def initialize(header, user, password)
#header = header
#user = user
#password = password
end
def call
str_pieces = #header["WWW-Authenticate"].split(/\"/)
{
"ACCEPT" => "application/vnd.api+json",
"Authorization" =>
"Digest username=\"#{#user}\","\
"realm=\"#{str_pieces[1]}\","\
"nonce=\"#{str_pieces[5]}\","\
"uri=\"/kinds/1\","\
"nc=00000001"\
"algorithm=MD5"\
"qop=auth"\
"opaque=#{str_pieces[7]}"
}
end
end
OBS: forgive me the unused password variable, i thought i could calculate something with it.
Here is an example string array from the first response header, aka str_pieces:
[
"Digest realm=",
"Application",
", qop=",
"auth",
", algorithm=MD5, nonce=",
"MTY2MDY4NTQ5MTpiMmE3N2FhYWJlMTYwYmI3ZTM3YzZkY2VlMjcxZmEyOA==",
", opaque=",
"5d5ba5ba4a787523d37a8ad54c64a8a9"
]
Bellow is the test on the spec archive:
describe "GET /show" do
it "renders a successful response" do
kind = Kind.create! valid_attributes
kind2 = Kind.create! valid_attributes2
get "http://www.example.com/kinds/1", headers: header
get "http://www.example.com/kinds/1", headers: DigestHeaderWriter.new(response.header, "Name", "secret").call
expect(response).to be_successful
expect(response.body).to include valid_attributes[:description]
expect(response.body).not_to include valid_attributes2[:description]
end
end
Basically it just stops at expect(response).to be_successful, and the header string just says that it's not an authorized request (401).
Maybe there's a whole other way to do it, either way i'm curious for a solution.

API Negatif Scenario with Rest-Assured and Junit

I want to make an API negative test scenario with Rest-Assured Library. I'm creating a get request for a data that doesn't exist. When I print this response to the console, I want to see the text 'not found' Because postman says this is the request body. But my test failed on get method. I am getting that error
io.restassured.internal.http.HttpResponseException: status code: 404, reason phrase: Not Found
Actually I know the status code is 404. But I can not test about it. How can i write that negative scenario
Response response = given().
when().
get("https://restful-booker.herokuapp.com/booking/1001");

Rails API 422 Unprocessable Entity: No verification key available, heroku

I created a Rails API with a JWT authentication system and deployed it to Heroku. When I request the endpoints locally, all seems to be working fine but when I make requests to the live endpoints (i.e the Heroku deployed app) I get a: 422 Unprocessable Entity server error and the response body looks like this:
{
"message": "No verification key available"
}
The class responsible for encoding and decoding the auth token is defined as follows:
class JsonWebToken
# secret to encode and decode token
HMAC_SECRET = Rails.application.secrets.secret_key_base
def self.encode(payload, exp = 24.hours.from_now)
# set expiry to 24 hours from the creation time.
payload[:exp] = exp.to_i
# sign token with application secret
JWT.encode(payload, HMAC_SECRET)
end
def self.decode(token)
# get payload, first index in decoded Array
body = JWT.decode(token, HMAC_SECRET)[0]
HashWithIndifferentAccess.new body
# rescue from all decode errors
rescue JWT::DecodeError => e
# raise custom error to be handled by custom handler
raise ExceptionHandler::InvalidToken, e.message
end
end
I have an endpoint /signup where I can make a POST request to register a new user and POST /todos which is accessible and available only to registered users. Making a registration request works perfectly fine, but when I try to make the POST request to the /todos endpoint it raises an error.
The association between user and suit is 1:m respectively.
Please if you have any idea on how I can fix this, I'll be very grateful, thanks : ).
I finally figured a way out by altering the Rails.application.secrets.secret_key_base to Rails.application.secret_key_base. For a more detailed review on this please check out this link. Hopefully, this will help someone facing a similar issue.
This was also my problem. After checking out my json_web_token.rb file, I figured out that I had written the following line:
HMAC_SECRET = Rails.application.secrets.secret_key_base
There is an extra secrets reference, which is causing the problem. It should be:
HMAC_SECRET = Rails.application.secret_key_base
But as far as I'm concerned, you managed to figure it out yourself!

Rails - Slack API OAuth Access - invalid_client_id

I'm building Slack integration for my Ruby on Rails application and I'm trying to get an access_token from the Slack API for my Slack App when a user clicks the Add to Slack button.
From Postman, I can successfully post the following:
https://slack.com/api/oauth.access?client_id=idgoes.here&client_secret=secretgoeshere&code=12345&pretty=1
However, within Rails I always get a response with invalid_client_id, regardless of the way I call the API. I have checked my ID is correct (a lot) and tried regenerating it, but I don't think that is the issue due to the postman success.
Within my get_oauth_access_token method I have tried the following implementations:
1.
rc = JSON.parse(HTTP.post('https://slack.com/api/oauth.access',
params: {
client_id: 'idgoes.here',
client_secret: 'secretgoeshere',
code: '12345'
}))
2.
response = Excon.post('https://slack.com/api/oauth.access',
headers: { 'Content-Type' => 'application/json; charset=utf-8' },
user: client_id, password: client_secret,
body: oauth_request_body.to_json)
Any implementation I try always ends up getting a invalid_client_id response.
I'm aware it may be something to do with environment config, but I'm not sure what would be helpful to debug, so please let me know what other information I can share. I'm running on localhost.
Update:
I just found out that many (maybe all) of the Slack APIs do not accept a JSON format body (which seems crazy seeing as they send a response in JSON.
Make sure to use x-www-form-urlencoded format body on your request or it will not work properly.
"Content-Type" => "application/x-www-form-urlencoded"
I use oauth2 gem to authorize. So I was able to get this to work by reading the slack documentation and using oauth2 in my controller:
class OauthController < ApplicationController
def authorize
options = {
site: 'https://slack.com/oauth/authorize'
}
client ||= OAuth2::Client.new(
'client-id',
'client-secret',
options
)
params = {
scope: 'incoming-webhook, commands',
redirect_uri: 'https://localhost:3000/oauth/callback'
}
redirect_to client.auth_code.authorize_url(params)
end
def authorize_callback
puts params["code"]
redirect_to root_url
end
end
Routes file:
get '/authorize', to: 'oauth#authorize'
get '/oauth/callback', to: 'oauth#authorize_callback'
Don't forget to set your callback url at Oauth settings on api.slack.com, I used localhost for testing purposes as you can see.

Issues sending a POST via Net::HTTP to a Battle.Net Community API End-Point (OAuth 2)

Versions:
Ruby 2.2.4
Rails 4.2
Omniauth-oauth2 1.3.1
Omniauth-bnet 1.1.0
Issue:
Trying to complete the authorization and token request process to Blizzard's Battle Net Community API. While I can get the authorization_code returned, when I attempt to construct a POST back to the token endpoint it keeps telling me that its an invalid request/internal server error or just returns back the following object: <Net::HTTPFound 302 Found readbody=true> which has a blank string for a response body. Details for how Blizzard recommends handling the OAuth 2 process are located here: Battle.net OAuth 2 Guide. The omniauth-bnet gem is the one Blizzard suggested but doesn't seem to handle the entire OAuth authorization and token process but I'll freely admit I'm brand new when it comes to anything OAuth related so I could be wrong.
Any help you all can provide would be very welcome!
Controller Code:
def index
client_id = ENV[BNET_CLIENT_ID]
client_secret = ENV[BNECT_CLIENT_SECRET]
uri = URI('https://us.battle.net/auth/token?
redirect_uri=https%3A%2F%2f127%2f0%2f0%2f1%3A3001%2Fauth%2Fbnet%2Fcallback
&grant_type=authorization_code
&code=' + params["code"])
req = Net::HTTP::Post.new(uri)
req.basic_auth(client_id, client_secret)
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') {|http| http.request(req)}
#bnet_response = res.body
end
Process:
Click link on index.html page which triggers the authorization process to start by sending a GET request to https://us.battle.net/oauth/authorize?client_id=&client_secret=&redirect_uri=&response_type=code
BNet API accepts the request and redirects user to Battle.Net Login screen
User authorizes app and is redirected (via redirect_uri) back to the index page with query parameters for the authorization_code
My app SHOULD make a POST request using the controller code above and the response should contain the actual access token.
This is just some hastily cobbled together code while I'm trying to get this working. I'll clean it up once I get over this little speed bump. I wouldn't hardcode the URI and such normally, just getting frustrated with things.
Things I've tried:
Using Rest-Client : There's a callback redirect that it can't handle apparently
Testing Postman : When using their OAuth 2 Authorization it works just fine, also works fine if I use Postman to get the authorization code (GET) and token (POST), so I'm assuming things work on the Blizz side and my code just sucks.
config/routes.rb
Rails.application.routes.draw do
root to: 'pages#index'
get '/auth/:provider/callback', to: 'pages#index'
end
I'm not familiar with the Battle.net API, however reading your process it seems you are getting an authorization code back from the redirect in the form of a query parameter (accessed by params[:code]) correct?
You also mention that this works using Postman indicating the flaw must be somewhere in the code.
I would suggest using the following snippet and let me know if it works. I would encourage using puts url after url = ... code to ensure the URI looks exactly as you want it (and has the correct code, client id, secret, redirect_uri).
require 'uri'
require 'net/http'
# Remember to change the redirect uri to match yours
redirect_uri = 'https://my-domain-name.com/auth/bnet/callback'
# Double check the environment variable names for BNET ID / Secret
url = URI("https://us.battle.net/oauth/token?redirect_uri=#{redirect_uri}&code=#{params[:code]}" \
"&grant_type=authorization_code&scope=wow.profile&client_id=#{ENV['BNET_CLIENT_ID']}" \
"&client_secret=#{ENV['BNET_CLIENT_SECRET']}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_body
Ensure your domain is accessible over https as this seems to be required.

Resources