I want to test interactive authentication with watir. I need to open browser once on selenium server, enter without user interaction his login/password (stored on server, user doesn't enter them, he just has to enter verification code), new text field with 'enter verification code' label appears, then system sends verification code to user and closes browser(here i need somehow to save session). User receives verification code and sends it to server, server opens new browser(restores somehow saved session) and enters verification code received from user.
I could keep browser open and just enter verification code in appeared text field but if user won't send me verification code that he received, browser will remain open, not good solution.
So, I tried something like this:
params = { login: 'userexample.com', password: '123456' }
adapter = Adapters::Test.new(params)
adapter.sign_in #opens browser, fills credentials fields, clicks 'get verification code', 'enter verification code' field appears
cookies = adapter.browser.cookies.to_a #save browser state
url = adapter.browser.url
adapter.browser.close
adapter = Adapters::Test.new(params)
adapter.browser.goto url
adapter.browser.cookies.clear
cookies.each do |saved_cookie|
adapter.browser.cookies.add(saved_cookie[:name], saved_cookie[:value])
end
adapter.browser.refresh #I should be on the same page with appeared 'enter verification code' field, but nothing happens after refresh, I am still on the main page with only login/password fields.
How can I save browser state, close it and then reopen with the same session?
def prepare_for_sign_in
browser.goto login_url
browser.text_field(:name => "login").set("admin")
browser.text_field(:name => "password").set("admin")
browser.a(:class => "enter").click
until browser.div(:text => /Welcome/).present? do
if browser.div(:class => 'error').text.include?("incorrect username or password")
raise InvalidCredentials.new("Invalid login or password.")
end
end
# here you need to sleep few secs or use similar conditional wait
Watir::Wait.until { browser.cookies.to_a.first[:name] == "JSESSIONID" }
params["interactive_data"] = {
"cookies" => JSON.parse(browser.cookies.to_a.to_json),
"proceed_url" => browser.url
}
end
def sign_in
restore_cookies(params["interactive_data"]["proceed_url"])
browser.text_field(:name => "sms").set('123456')
browser.a(:text => "Proceed").click
end
def restore_cookies(url)
browser.goto url
browser.cookies.clear
params["interactive_data"]["cookies"].each do |cookie|
browser.cookies.add(
cookie["name"],
cookie["value"],
{
domain: cookie["domain"],
path: cookie["path"],
expires: cookie["expires"],
secure: cookie["secure"]
}
)
end
browser.goto url
browser.refresh
end
There is some more source code, but I can not share all of it, but logic is similar
Related
I used a front-end and back-end API server to implement a Ruby/Sinatra web application. The form will post to the '/login' route in the front-end app.rb:
post '/login' do
uri = URI.join("http://#{settings.api}:#{settings.api_port}",
"/user/", "validate")
response = Net::HTTP.post_form(
uri, 'email' => params[:email],
'password' => params[:password])
h = response.code == "200" || response.code == "401" ?
JSON.parse(response.body) : {}
if h["status"] == "success"
# Save the user id inside the browser cookie.
# This is how we keep the user
# logged in when they navigate around our website.
session[:user_id] = h["user_id"]
puts session[:user_id]
redirect '/home'
else
# If user's login doesn't work, send them back to the login form.
flash[:notice] = "Login failed due to #{h["status"]}"
redirect '/login'
end
end
The post request and its parameters are sent through HTTP to the back-end server. And the back-end API server will respond with JSON which has a status field to suggest if the user is authenticated successfully.
I have the following message in the browser that says "connection not secure".
enter image description here. Is there extra safety configuration that I have to include in the front-end app.rb?
You can try adding the following configrations in your app.rb file:
configure :development, :test do
set :force_ssl, true
end
configure :production do
set :force_ssl, true
end
See "Forcing SSL in a Sinatra App" about forcing SSL in Sinatra applications and how it could be helpful to your situation.
I'm using the watir gem to login to salesforce using the omniauth-salesforce gem in a Sinatra app. While using a normal browser, it follows the 303 redirect just fine. However, the Watir::Browser instance of phantomjs does not.
post '/authenticate/:provider' do
case params[:provider].downcase
when 'salesforce'
auth_params = {
:display => 'page',
:immediate => 'false',
:scope => 'full',
}
auth_params = URI.escape(auth_params.collect{|k,v| "#{k}=#{v}"}.join('&'))
redirect "/auth/salesforce?#{auth_params}"
when 'box'
oauth_url = Boxr::oauth_url(
URI.encode_www_form_component(CredService.creds.box.utility_app.token),
client_id: CredService.creds.box.utility_app.client_id
)
redirect oauth_url
when 'sandbox'
auth_params = {
display: 'page',
immediate: 'false',
scope: 'full',
}
auth_params = URI.escape(auth_params.collect{|k,v| "#{k}=#{v}"}.join('&'))
redirect "/auth/salesforcesandbox?#{auth_params}"
end
end
When I authenticate via box usig Watir::Browser.new(:phantomjs), I have no issues navigating to a login page and putting in credentials. I believe it's because the redirect path is direct to app.box.com, whereas the omniauth redirect is first internal (/auth/salesforce?#{auth_params}) then it redirects again to the salesforce domain.
Any thoughts on the matter would be appreciated. I've used binding.pry w/ byebug and traversed the sinatra/rack code path, but I can't descern what is going on.
here is a link to the omniauth-salesforce login example page
I'm creating an application, which has authentication based on external API with login/register methods. I have a simple controller called RegistrationsController which fires a request using Curb.
This is the controller:
class RegistrationsController < ApplicationController
def new
end
def create
if params[:user][:email].present? && params[:user][:password].present? && params[:user][:phone].present? && params[:user][:login].present?
# API request
password = params[:user][:password]
body = {
"register" => {
"password" => password,
"email" => params[:user][:email],
"phone" => params[:user][:phone],
"login" => params[:user][:login]
}
}
c = Curl::Easy.http_post("http://domain.com/register", body.to_json
) do |curl|
curl.headers['Content-Type'] = 'application/json'
curl.headers['application'] = 'appname'
curl.headers['device'] = 'www'
end
c.perform
response_body = JSON.parse(c.body_str)
throw response_body # This line ALLWAYS gives me 'login taken' error
return
else
#user = User.new(params[:user])
render action: "new", notice: 'Error'
end
end
end
(I also have a views/registrations/new.html.slim view with a simple form but it's not important right now.)
My routes look like this:
match 'users/sign_up' => 'registrations#new', :via => :get, :as => :user_register
match 'users/sign_up' => 'registrations#create', :via => :post, :as => :user_create
My application, after I click the "Register" button on the registrations#new page, is triggering the Curb request two times. As a result, I'm always getting a 'login taken' error. The user is registered successfully but I'm not getting any result from the first request, just from the second one.
It's somehow caused by Rails and I'm 100% sure about it because it can be seen in the API server logs that the request is triggered twice. Also, I have exactly the same script written in PHP and, in there, the registration works fine.
In my Rails dev console, the request is triggered just one time so it's really strange.
Does anyone have any idea what is going on here?
I found the answer.
If anyone struggles with something similar, it was caused by the c.perform line. Just remove it and it will work fine.
I should study the docs better in the future.
I want to login to facebook in IFRAME(Facebook Apps).
Go http://apps.facebook.com/oauthtwosample/ with logoff and click "login" link.
Response header have Location Header when redirect permissions request dialog page.
Chrome screenshot below:
http://gyazo.com/0f4988158cb0e0a9f52545374540de96
If you have any ideas, let me know.
Source:
require 'rubygems'
require 'sinatra'
require 'oauth2'
require 'json'
##client = OAuth2::Client.new(
'xxxxxxxxxxxxx',
'xxxxxxxxxxxxxxxxxxxxxxxx',
:site => 'https://graph.facebook.com'
)
def redirect_uri
uri = URI.parse(request.url)
uri.path = '/auth/facebook/callback'
uri.query = nil
uri.to_s
end
get '/' do
'login'
end
post '/' do
'login'
end
get '/auth/facebook' do
redirect ##client.web_server.authorize_url(
:redirect_uri => redirect_uri,
:scope => 'email,offline_access'
)
end
get '/auth/facebook/callback' do
access_token = ##client.web_server.get_access_token(
params[:code],
:redirect_uri => redirect_uri
)
user = JSON.parse(access_token.get('/me'))
user.inspect
end
This is because of redirting user without permission you can easly
solve it by adding target="_top" to link.
login
I am trying to implement facebook authentication for an app with warden, after the user allows facebook auth and redirects to my app callback with the token I get a 400 while consuming the api. My warden strategy is this:
class Facebook < Warden::Strategies::Base
def client
#client ||= OAuth2::Client.new MyApp::Facebook::AppID, MyApp::Facebook::AppSecret, :site => 'https://graph.facebook.com'
end
def params
#params ||= Rack::Utils.parse_query(request.query_string)
end
def authorize_url
client.web_server.authorize_url :redirect_uri => request.url, :scope => 'email,publish_stream'
end
def authenticate!
throw(:halt, [302, {'Location' => authorize_url}, []]) unless params['code']
facebook = client.web_server.get_access_token params['code'], :redirect_uri => request.url
rescue OAuth2::HTTPError => e
puts e.response.body
end
end
Strategies.add :facebook, Facebook
The result of printing the response body is this:
{"error":{"type":"OAuthException","message":"Error validating client secret."}}
I am pretty shure the app id and app secret are the ones provided by FB.
Thanks.
I've seen that error message many times. Here are the things I would double check:
your domain is the same as what you listed in the facebook callback url
the app id is correct (actually print this out on a page, sometimes y
the app secret is correct
Add redirect_uri while creating the object of facebook that will fix the issue.
Redirect the user to https://www.facebook.com/dialog/oauth?client_id=YOUR_APP_ID&redirect_uri=YOUR_URL
After user click allow, it'll hit our Redirect Uri
At that point we'll get the code and we need to do a server side HTTP Get to the following Url to exchange the code with our oAuth access token:
https://graph.facebook.com/oauth/access_token?
client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&
client_secret=YOUR_APP_SECRET&code=THE_CODE_FROM_ABOVE
Now at step 3, I kept on getting Http 400 response back.
So after some research, I found out that on that redirect_uri that we submitted on step 3 doesn't do anything but validate the request. Thus, the value need to match with step 2.
I also get the same error and i resolved by doing as below:
double check your client_id, client_secret, redirect_uri.
Add Accept: "application/json" header to thye request
fetch(
`https://graph.facebook.com/v15.0/oauth/access_token?client_id=${process.env.FACEBOOK_APP_ID}&redirect_uri=${process.env.FACEBOOK_REDIRECT_URI}&client_secret=${process.env.FACEBOOK_APP_SECRET}&code=${code}`,
{
method: "GET",
headers: {
Accept: "application/json",
},
}
)