Login to external site from Rails - ruby-on-rails

I would like to login to an external https site, through rails based on user/password credentials saved into a rails database. Something like a single sign on. The external site does not provide an API to login; only a login form. Their docs say you can post the credentials to their login form by loading the email and password to the form and then pressing ok.
But if I do that, then by viewing the source code of the login form, someone may find out the login credentials. I have looked into Mechanize and loading cookies like here Submitting POST data from the controller in rails to another website and Rails 3 - Log into another site and keep cookie in session but it does not seem right.
Is there a way to automatically load the credentials from the controller and post to the external site immediately in order to login to that site?
Thank you in advance

I would use Oauth2. Here is a good wrapper: https://github.com/intridea/oauth2

I was able to do this via mechanize. For facebook for example, which uses https, the code is shown below
In my user_controller.rb:
def face_book
#website = 'https://www.facebook.com/login.php?login_attempt=1&lwv=110'
agent = Mechanize.new
agent.log = Logger.new "mechanize.log"
agent.user_agent_alias = 'Mac Safari'
agent.follow_meta_refresh = true
agent.redirect_ok = true
login_page = agent.get (#website)
login_form = login_page.forms.first
email_field = login_form.field_with(name: "email")
password_field = login_form.field_with(name: "pass")
email_field.value = 'PUT_YOUR_EMAIL_HERE'
password_field.value = 'PUT_YOUR_PASSWORD_HERE'
home_page = login_form.click_button
#blah = agent.get("https://m.facebook.com/")
end

Related

prevent user login after registration using django-allauth

i'm using django-allauth for my django app. by default, when a user successfully sign's up, they are automatically logged in. how do you override the default behaviour and prevent the user from logging in after after successful signup. After the user signs up, he/she must be redirected to the login page. ive disabled email verification. Thank you.
# settings.py
LOGIN_REDIRECT_URL = 'welcome'
ACCOUNT_AUTHENTICATED_LOGIN_REDIRECTS = False
ACCOUNT_LOGOUT_REDIRECT_URL = 'thanks'
ACCOUNT_EMAIL_REQUIRED = False
ACCOUNT_EMAIL_VERIFICATION = 'none'
If you don't need the email verification, you can skip the login like this:
First in your urls.py, you must override the url to the default SignupView with a url to your own view:
url(r^'accounts/signup/$', views.CustomSignupView.as_view(), name="account_signup")
Then in your views.py, you have a custom view that will return a path to your frontpage instead of continuing to login the user.
class CustomSignupView(SignupView):
def form_valid(self, form):
self.user = form.save(self.request)
return redirect('/frontpage')

Linkedin OAuth authentification with React Frontend + Rails API

So far my website has been using fullstack views generated directly by Rails, and for linkedin authentication I used a redirect_uri routed to a Devise::OmniauthCallbacksController to handle the logic.
GET https://www.linkedin.com/oauth/v2/authorization?redirect_uri=my_devise_omniauth_callback_url
I am wondering how to migrate this to a standalone React frontend + a standalone Rails server. The React app should "spawn" a linkedin popup for authorization, and wait until all the authorization process is done before closing itself and proceeding with registration on the main window.
I have been through the Linkedin OAuth guide and I see the way from approving the connection to getting user info is quite long. I am happy that Devise/Omniauth does most of the job for me server-side and I'd rather keep it this way, instead of coding that logic in the frontend.
(By the way, is it safe to assume the Linkedin OAuth flow be similar to the Google one mentionned in this answer ?)
I am unsure about whether this can be done the way I see it on the React app (especially the communication of data between the linkedin popup window and the main react view). Also from what I understand the omniauth gem in rails expects to receive the one-time token from the OAuth provider before it can query the provider twice more (first time to exchange the access token, second time to get user info). Would the following work ?
Assume my React Client app is hosted on client.example.com
Assume my server api is hosted on api.example.com
The React app opens a popup windows, that is used to go to the Linkedin auth URI with
(1) A redirect uri that would point directly to api.example.com
(2) A redirect_uri on client.example.com, and my React client would then have to forward the token to api.example.com
The authorization code somewhat reaches my server api.example.com, which gets an access code and retrieves user data from Linkedin. It returns to the browser an identity_id which can be used for the registration
The identity_id is actually returned to the popup window, and transferred back to the main React app (how ?)
I had the same problem and I found an hacky but interesting solution :-)
(I use all the OAuth logic from devise and omniauth-linkedin gems.)
In my application, you can start to fill up a form and you need to login before save it. I needed a way to log the user without loosing form data and without reloading the page.
When the user visit the page, he is given a unique uuid to identify him. This uuid is used to start a websocket connection so I can push data directly to this tab later.
I open the LinkedIn OAuth in a new tab with javascript window.open() so I can close this tab with window.close().
You can pass additional parameters to the OAuth authentication, I pass the unique uuid so I can recover it when the authentication is a success and with this uuid I can notify the first tab by sending a message via websocket (In my application I send the user infos to update state with current user).
After authentication, I redirect the user on a page containing only window.close().
Setup LinkedIn OAuth in Rails
You will need a functional Omniauth/Devise authentication working.
omniauth_callback_controller.rb
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def linkedin
user = User.connect_to_linkedin(request.env["omniauth.auth"], current_user)
guest_guid = request.env["omniauth.params"]["guestGuid"]
if user.persisted?
ActionCable.server.broadcast("guest:#{guest_guid}", { user: UserSerializer.new(user).to_h })
sign_in(user)
redirect_to landing_home_index_path
end
end
end
user.rb
def self.connect_to_linkedin(auth, signed_in_resource = nil)
user = User.where(provider: auth.provider, linkedin_uid: auth.uid).first
if user
return user
else
registered_user = User.where(email: auth.info.email).first
if registered_user
return registered_user
else
user = User.create(lastname: auth.info.last_name, firstname: auth.info.first_name,
provider: auth.provider, linkedin_uid: auth.uid, email: auth.info.email,
linkedin_token: auth.credentials.token, linkedin_secret: auth.credentials.secret,
linkedin_picture: auth.extra.raw_info.pictureUrl, password: Devise.friendly_token[0, 20])
end
end
end
routes.rb
devise_for :users, controllers: {
omniauth_callbacks: "omniauth_callbacks",
sessions: "users/sessions"
}
Now if you visit /users/auth/linkedin you will be able to log/create user with LinkedIn OAuth.
Websocket connection
create_job_offer_channel.rb
class CreateJobOfferChannel < ApplicationCable::Channel
def subscribed
stream_from "guest:#{params[:guest]}"
end
def unsubscribed
end
def receive(data)
ActionCable.server.broadcast("guest:#{params[:guest]}", data)
end
end
create_job_offer.js.coffee
class window.CreateJobOffer
constructor: (params) ->
self = #
#channel = App.cable.subscriptions.create {
channel: "CreateJobOfferChannel", guest: params["guest"]
}, self
#onReceive = params["onReceive"] || null
received: (data) =>
#onReceive(data) if #onReceive
React frontend
Link to LinkedIn OAuth (with devise and omniauth)
<div className="btn-linked-in">
<i className="fa fa-linkedin-square"></i>
<span onClick={() => open(`/users/auth/linkedin?guestGuid=${guestGuid}`)}>
Login with LinkedIn
</span>
</div>
Hope this help :)

Access Sorcery oauth response data

I'm using Sorcery gem with External submodule. For some reason I'm not getting an email back from Facebook and I'm pretty sure I have things configured correctly. I'm trying to troubleshoot this further but I can't figure out how to read what data IS being returned via oauth to verify where things are breaking down. Where can I pry in and read this info? Thanks!
Here is my sorcery config.
Rails.application.config.sorcery.submodules = [:external]
Rails.application.config.sorcery.configure do |config|
config.external_providers = [:facebook, :google]
config.facebook.key = "#{Rails.application.secrets.sorcery_facebook_key}"
config.facebook.secret = "#{Rails.application.secrets.sorcery_facebook_secret}"
config.facebook.callback_url = "#{Rails.application.secrets.sorcery_facebook_callback_url}"
config.facebook.user_info_path = "me?fields=email,first_name,last_name"
config.facebook.user_info_mapping = {:email => "email"}
config.facebook.access_permissions = ["email"]
config.facebook.scope = "email"
config.facebook.display = "popup"
config.facebook.api_version = "v2.5"
config.user_config do |user|
user.authentications_class = Authentication
end
config.user_class = User
end
Well, technically this answers the question of how to find out what is being returned.
Inside your oauth controller if you call access_token.get('me?fields=email') or whatever fields you're wanting you'll get a response with a URL field set. Copy that URL into a browser and you'll get a JSON list of your data. In my case I get nothing with email but I'm able to return first_name, last_name, name. Not quite sure why I still can't get email, but hopefully this helps somebody troubleshoot in the future.
Another way would be to build the URL yourself if you have the access_token available.
https://graph.facebook.com/me?access_token=<access token goes here>&fields=first_name,last_name,email
Access token is retrievable with #access_token.token from oauth controller.
UPDATE
So silly...I had the config correct, but apparently had never logged out of Facebook since I'd made the proper corrections. Logging out and having oauth connect again seems to have fixed things.

Unable to login to Application using CAS and Spring security

1.
I have setup a CAS server up and running at port: 8443 url -> https://ekansh/cas.
I can see the login page and i am successfully able to login using mysql database user table credentials. and even logout and see status.
I created a demo grails app, installed spring security plugin and created user role mappings by s2-quickstart. and scaffolding domains.
I added the
compile ":spring-security-core:2.0-RC4"
compile ":spring-security-cas:2.0-RC1"
dependencies.
Added configurations in Config.grovy
grails.plugin.springsecurity.cas.active = true
grails.plugin.springsecurity.cas.loginUri = '/login'
grails.plugin.springsecurity.cas.sendRenew = false
grails.plugin.springsecurity.cas.serviceUrl = 'http://ekansh:8095/app1/j_spring_cas_security_check'
grails.plugin.springsecurity.cas.serverUrlEncoding = 'UTF-8'
grails.plugin.springsecurity.cas.key = 'grails-spring-security-cas'
grails.plugin.springsecurity.cas.artifactParameter = 'ticket'
grails.plugin.springsecurity.cas.serviceParameter = 'service'
grails.plugin.springsecurity.cas.filterProcessesUrl = '/j_spring_cas_security_check'
grails.plugin.springsecurity.cas.proxyCallbackUrl = 'http://ekansh:8095/app1/secure/receptor'
grails.plugin.springsecurity.cas.useSingleSignout = true
grails.plugin.springsecurity.cas.serverUrlPrefix = 'https://ekansh:8443/cas'
grails.plugin.springsecurity.cas.proxyCallbackUrl = 'http://ekansh:8095/app1/secure/receptor'
grails.plugin.springsecurity.cas.proxyReceptorUrl = '/secure/receptor'
grails.plugin.springsecurity.logout.afterLogoutUrl ='https://ekansh:8443/cas/logout?url=http://ekansh:8095/app1/'
grails.plugin.springsecurity.providerNames = ['casAuthenticationProvider']
Nw when i run this app, i get redirected to cas server page, i enter the credentials, it logs me into cas server, but it sends me to the spring security login page with message that
Sorry, we were not able to find a user with that username and password. And i am not even able to sign in to the application from this point.
What am i missing ? Why am i getting spring security login page.
I also found that when i comment line grails.plugin.springsecurity.providerNames = ['casAuthenticationProvider'], i am able to login to the system. I have not altered the casAuthenticationProvider.
Any help would be appriciated.
I found the answer to my question after a lot of research. Basically i did mess up with the configurations of the cas server.
The user was getting logged into the cas server but a ticket was not being generated for the same user, thus it was still sending a user not authenticated response back to the application and spring security, was redirecting to the login page.

Rails EOF Error when using HTTP.get_response to retrieve Facebook access token

I trying to implement a Login with Facebook feature on my site, and hitting a roadblock trying to get the access token back from Facebook. Here is my code:
if params[:error_reason] == "user_denied" then
flash[:error] = "To login with Facebook, you must click 'Allow' to let the site access your information"
redirect_to :login
elsif params[:code] then
token_uri = URI.parse("https://graph.facebook.com/oauth/access_token?client_id=****************&redirect_uri=http://localhost:3000/auth/fblogin&client_secret=***************&code="+URI.escape(params[:code]))
response = Net::HTTP.get_response(token_uri)
session[:response] = response
data = ActiveSupport::JSON.decode(response)
access_token = data[:access_token]
flash[:error] = access_token
redirect_to :register
end
This is inside a fblogin controller function that is the target of the initial redirect to get an authorization code (the params[:code]).
But when I run through this, I get the following error:
EOFError in AuthController#fblogin
on the Net::HTTP.get_response(token_uri) line. I've searched all over, and can't find anything to indicate what this means. Could it be the obscure characters Facebook uses in their access tokens? I'm totally lost!
You are receiving an EOFError because you are trying to connect to an https URL using code that only works with http. See the section entitled "SSL/HTTPS request" at this Net::HTTP Cheat Sheet for the basics.
However, I would recommend using a third-party library to manage this for you, such as OAuth2 for utilizing Facebook's OAuth2 API, where you'd write code like this:
def client
OAuth2::Client.new('app_id', 'app_secret', :site => 'https://graph.facebook.com')
end
# in your callback code:
access_token = client.web_server.get_access_token(params[:code], :redirect_uri => 'http://localhost:3000/auth/fblogin')
user = JSON.parse(access_token.get('/me'))
If you really want to make the requests yourself, you can look at libraries like Faraday to execute the HTTPS requests for you.

Resources