omniauth google_oauth2 the profile image is not present in the authhash - ruby-on-rails-3

This is written in omniauth.rb an initializer.
Rails.application.config.middleware.use OmniAuth::Builder do
provider :google_oauth2,ID,SECRET,
{
:approval_prompt => '',
:scope => 'http://gdata.youtube.com,https://www.googleapis.com/auth/userinfo.email,https://www.googleapis.com/auth/userinfo.profile'
}
The returned auth hash does not have IMAGE element in the "info", why?????????
Replaced original info with x in the below HASH
*********************
--- !ruby/hash:OmniAuth::AuthHash
provider: google_oauth2
uid: 'xxxxxxxxxxxxxxxxxxxx'
info: !ruby/hash:OmniAuth::AuthHash::InfoHash
name: xxxx xxx
email: xxxxxxxxxx
first_name: xxxxxx
last_name: xxxxxxx
credentials: !ruby/hash:Hashie::Mash
token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
expires_at: 1365434778
expires: true
extra: !ruby/hash:Hashie::Mash
raw_info: !ruby/hash:Hashie::Mash
id: 'xxxxxxxxxxxxxxxxxxxxxxxxxxx'
email: xxxxxxxxxx.xxx#gmail.com
verified_email: true
name: xxxx xxxx
given_name: xxx
family_name: xxx
link: https://plus.google.com/xxxxxxxxxxx
gender: male
locale: en
*********************
I want the profile image, what am I doing wrong?
Also tried,
{:scope => 'userinfo.email,userinfo.profile'}
Not working!!

Not sure what that scope is doing, but I've just solved getting google info for myself.
Is that information the actual params sent to rails, or is it the saved user hash?
If it's not the actual params you get on login, you can use:
# sessions_controller.rb
raise env["omniauth.auth"].to_yaml
That'll show you everything that google is sending you.
If it's the user and If you've followed Railscasts like I was doing, then check that you've created a field to save the pics and that you've set the field to save the info from the hash. I did this:
# sessions_controller.rb
def create
user = User.from_omniauth(env["omniauth.auth"])
user.image = env["omniauth.auth"]['info']['image']
user.save
session[:user_id] = user.id
redirect_to root_url, :notice => "Signed in!"
end
If that's not what you're needing, can you be more specific?

Related

Devise Token Auth / Angular2-Token, update password, Completed 401 Unauthorized

I'm having troubles restoring password with devise_token_auth. and Angular2-Token. I'm successfully receiving the email with the link to update my password. But I'm getting an 401 Unauthorized response when submiting the new password.
Front end. I'm getting the token from the URL with urlParams.get('token')
onPasswordUpdate() {
let token = this.urlParams.get('token');
var obj = Object.assign(this._updatePasswordData, { reset_password_token: token })
this._tokenService.patch('auth/password/', obj ).subscribe(
res => res,
error => error
);
}
Back end response.
Started PATCH "/api/auth/password/" for 127.0.0.1 at 2016-12-01 21:17:48 +0100
Processing by DeviseTokenAuth::PasswordsController#update as JSON
Parameters: {"reset_password_token"=>"[FILTERED]", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}
Completed 401 Unauthorized in 1ms (Views: 0.4ms | ActiveRecord: 0.0ms)
In the link of the email I get the following token : reset_password_token=HneZDoKTMCLF3_SLfnxy
When I visit the link, the user record gets updated with the following attributes :
reset_password_token: "aa3cba76c7b1d8f78cde6856f43e1cce57f5fc8e5301842733de677eff909bc1"
tokens: {}
Then in the browser URL I get the following token=agejaip2SqOp9nvwE1GAHQ&uid
And then the user record get updated with the following attribues :
...
reset_password_token: "HneZDoKTMCLF3_SLfnxy",
tokens: {"pv9i1BDTM29ezep0KSPzpA"=>{"token"=>"$2a$10$cS9gbe9UBICcgphZHRAENOMS6NlEe0Em1cNufY3LSRTPE.hRMabvi", "expiry"=>1481834221}}
...
It seems to me that the token I get back in URL is not correct.
Those anyone have an idea ?
Sorry It's a bit hard to explain.
Many thanks.
rails (4.2.4)
devise_token_auth (0.1.34)
devise (= 3.5.1)
angular2-token: 0.2.0-beta.1
I faced similar challenges recently, and this was how I solved it.
Expose the 'access-token', 'expiry', 'token-type', 'uid', 'client' for your backend. Check here and here
config.middleware.use Rack::Cors do
allow do
origins '*'
resource '*',
:headers => :any,
:expose => ['access-token', 'expiry', 'token-type', 'uid', 'client'],
:methods => => [:get, :post, :options, :delete, :put, :patch]
end
end
Set your redirect_url of path: /password, method: POST. Check info here
We need to modify the reset_password_instructions.html.erb to point it to the api GET /auth/password/edit. More information provided here.
E.g. if your API is under the api namespaces:
<%= link_to 'Change my password', edit_api_user_password_url(reset_password_token: #token, config: message['client-config'].to_s, redirect_url: message['redirect-url'].to_s) %>

omniauth-facebook not returning email

We just updated our ruby version to 2.0 from 1.9.3. From what I can tell we haven't updated omniauth omniauth-facebook or oauth in the upgrade. The upgrade however broke facebook login. Looking at the logs I don't see an email coming back in the omniauth hash.
Here's my initializer, which loads my yml file where I define the secret and whatnot.
omniauth.rb initializer
class OmniAuthConfig
class << self
def load(file = 'omniauth.yml')
configuration_file = File.join(Rails.root, 'config', file)
if File.exists?(configuration_file)
File.open(configuration_file) do |configuration|
configuration = YAML.load(configuration)[Rails.env.to_sym]
configuration.each do |key, value|
cattr_accessor(key)
send("#{key}=", value)
end
end
end
end
end
end
OmniAuthConfig.load
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook,
OmniAuthConfig.facebook_api_key,
OmniAuthConfig.facebook_api_secret,
scope: 'email',
client_options: { ssl: { ca_file: "/etc/ssl/certs/ca-certificates.crt" } }
end
Censored logs:
--- !ruby/hash:OmniAuth::AuthHash
provider: facebook
uid:
info: !ruby/hash:OmniAuth::AuthHash::InfoHash
image: http://graph.facebook.com//picture?type=square
credentials: !ruby/hash:OmniAuth::AuthHash
token: HUGE_TOKEN_STRING
expires_at: 1485547306
expires: true
extra: !ruby/hash:OmniAuth::AuthHash
raw_info: !binary |-
HASH_THINGY

Rails/Devise/SAML Metadata Incorrect (not working with PingFederate)

Let me preface this question by saying that I'm new to SAML and barely understand how it works.
The Setup
I'm using the devise_saml_authenticatable gem with a Rails 4 app to achieve SSO. The Rails app acts as the service provider (SP). To test my setup, I created a OneLogin developer account and set up a SAML Test Connector (IdP w/attr w/ sign response) using the following attributes:
Configuration Tab
Audience: mysubdomain.onelogin.com
Recipient: http://mysubdomain.myapp.local:3000/saml/auth
ACS (Consumer) URL Validator: ^http://mysubdomain.myapp.local:3000/saml/auth$
ACS (Consumer) URL: http://mysubdomain.myapp.local:3000/saml/auth
Single Logout URL: http://mysubdomain.myapp.local:3000/saml/idp_sign_out
SSO Tab
Issuer URL: https://app.onelogin.com/saml/metadata/589819
SAML 2.0 Endpoint (HTTP): https://mysubdomain.onelogin.com/trust/saml2/http-post/sso/589819
SLO Endpoint (HTTP): https://mysubdomain.onelogin.com/trust/saml2/http-redirect/slo/589819
SAML Signature Algorithm: SHA-1
SHA Fingerprint: 60:9D:18:56:B9:80:D4:25:63:C1:CC:57:6D:B9:06:7C:78:BB:2C:F1
X.509 Certificate:
-----BEGIN CERTIFICATE-----
MIIEFzCCAv+gAwIBAgIUQYRVa1MQpUh0gJaznmXSF/SPqnowDQYJKoZIhvcNAQEF
BQAwWDELMAkGA1UEBhMCVVMxETAPBgNVBAoMCEZpcm1QbGF5MRUwEwYDVQQLDAxP
bmVMb2dpbiBJZFAxHzAdBgNVBAMMFk9uZUxvZ2luIEFjY291bnQgOTI1MzEwHhcN
MTYwOTIxMTU0NzQwWhcNMjEwOTIyMTU0NzQwWjBYMQswCQYDVQQGEwJVUzERMA8G
A1UECgwIRmlybVBsYXkxFTATBgNVBAsMDE9uZUxvZ2luIElkUDEfMB0GA1UEAwwW
T25lTG9naW4gQWNjb3VudCA5MjUzMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBALGVgocBj0ciHM3uKlWIcofPhOtzfJw1XpAdNynAvPtbCl7WE5+sLBoQ
ZF+oZ7Dl+wRW6DHMJCl9DdKcOaQA6/gr5bwt78IzZ8hWMoKQEPih+E0km6rKLYA8
M52vxtJxGs8Iqx60QvPEePQFMOA+xg73OExfM7W5LnXwNz/Pxgsr3lBif5oCC76j
SaTCFroV+TSjfOaYMW/lZrsS79KRIzA9I5XwUBe3bC8bsfQmZXgddCrkQUNSGGaS
7/jtFUlQ94+lAL+l3yoAiNAE6+mt48qqmyLfkKibXvnZ8dwuO272wpY4fEM+vFRy
pYrTajqvhY3hYIq8dLw3ominE5VECl8CAwEAAaOB2DCB1TAMBgNVHRMBAf8EAjAA
MB0GA1UdDgQWBBSxiuvTPxwOhh2pupID+tuyKCeceTCBlQYDVR0jBIGNMIGKgBSx
iuvTPxwOhh2pupID+tuyKCeceaFcpFowWDELMAkGA1UEBhMCVVMxETAPBgNVBAoM
CEZpcm1QbGF5MRUwEwYDVQQLDAxPbmVMb2dpbiBJZFAxHzAdBgNVBAMMFk9uZUxv
Z2luIEFjY291bnQgOTI1MzGCFEGEVWtTEKVIdICWs55l0hf0j6p6MA4GA1UdDwEB
/wQEAwIHgDANBgkqhkiG9w0BAQUFAAOCAQEAYBe+5d3zpLZ7fcf3l3rXYeIxcpN+
9D2YZCbxsrBhY2Am4YE9nN+RaJXeDqeRBNtpayCZVxfHnXexRo1n7wxwTmosiydi
9yE7SY2xZf+3feQreF25atnn4tzVhxYONaX1njZMIt/TNa7A9aeDfHSD+vwSuYYB
hGxKT6HOkEAEBiXCZ/FcVNiB0D8bRwQhiJ3BTzXDfqHrmq8QYdn3Ejlqo62vMl6W
XeMXUoyv6cUc64Ap6E+XtEQI1E8YB5R8GtTs3Y1Oa2dD6yWyCyVJ20+Hi7IWAqXC
EfqstqXB7FoQ2rAt39cepnu1SOarvEYDMwYIaVNF3hoyodBybJJsAwAnCQ==
-----END CERTIFICATE-----
In my devise.rb I have the following configuration:
config.saml_create_user = false
config.saml_update_user = true
config.saml_default_user_key = :email
config.saml_session_index_key = :session_index
config.saml_use_subject = true
config.idp_settings_adapter = IdPSettingsAdapter
config.idp_entity_id_reader = DeviseSamlAuthenticatable::DefaultIdpEntityIdReader
Here is my IdPSettingsAdapter:
class IdPSettingsAdapter
def self.settings(idp_entity_id)
company = Company.find_by(idp_entity_id: idp_entity_id)
if company.present?
{
assertion_consumer_service_url: company.assertion_consumer_service_url,
assertion_consumer_service_binding: company.assertion_consumer_service_binding,
name_identifier_format: company.name_identifier_format,
issuer: company.issuer,
idp_entity_id: company.idp_entity_id,
authn_context: company.authn_context,
idp_slo_target_url: company.idp_slo_target_url,
idp_sso_target_url: company.idp_sso_target_url,
idp_cert_fingerprint: company.idp_cert_fingerprint
}
else
{}
end
end
end
Note that my user model Contact belongs_to Company, and that the SSO settings are stored in the Company model.
Here are my saml routes:
devise_for :contacts, skip: :saml_authenticatable, controllers: {
registrations: "registrations",
sessions: "sessions",
passwords: "passwords",
confirmations: "confirmations"
}
devise_scope :contact do
get '/sign_in' => 'sessions#new'
get '/sign_out' => 'sessions#destroy'
# SSO Routes
get 'saml/sign_in' => 'saml_sessions#new', as: :new_user_sso_session
post 'saml/auth' => 'saml_sessions#create', as: :user_sso_session
get 'saml/sign_out' => 'saml_sessions#destroy', as: :destroy_user_sso_session
get 'saml/metadata' => 'saml_sessions#metadata', as: :metadata_user_sso_session
match 'saml/idp_sign_out' => 'saml_sessions#idp_sign_out', via: [:get, :post]
end
Lastly here is my SamlSessionsController:
require "ruby-saml"
class SamlSessionsController < SessionsController
include DeviseSamlAuthenticatable::SamlConfig
skip_before_filter :verify_authenticity_token, raise: false
before_action :authorize_viewer, except: [:metadata]
protect_from_forgery with: :null_session, except: :create
def new
idp_entity_id = Company.friendly.find(#_request.env['HTTP_HOST'].split('.')[0]).idp_entity_id
request = OneLogin::RubySaml::Authrequest.new
action = request.create(saml_config(idp_entity_id))
redirect_to action
end
def metadata
idp_entity_id = Company.friendly.find(#_request.env['HTTP_HOST'].split('.')[0]).idp_entity_id
meta = OneLogin::RubySaml::Metadata.new
render :xml => meta.generate(saml_config(idp_entity_id)), content_type: 'application/samlmetadata+xml'
end
def create
#idp_entity_id = Company.friendly.find(#_request.env['HTTP_HOST'].split('.')[0]).idp_entity_id
response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], settings: saml_config(#idp_entity_id))
if !response.is_valid?
puts "SAML FAILED WITH ERROR: "
puts response.errors
end
super
end
def idp_sign_out
company = Company.friendly.find(request.subdomain.downcase)
idp_entity_id = Company.friendly.find(#_request.env['HTTP_HOST'].split('.')[0]).idp_entity_id
if params[:SAMLRequest] && Devise.saml_session_index_key
saml_config = saml_config(idp_entity_id)
logout_request = OneLogin::RubySaml::SloLogoutrequest.new(params[:SAMLRequest], settings: saml_config(idp_entity_id))
resource_class.reset_session_key_for(logout_request.name_id)
# binding.pry
sign_out current_contact if contact_signed_in?
redirect_to company.after_slo_url.present? ? company.after_slo_url : 'https://' + company.issuer
# redirect_to generate_idp_logout_response(saml_config(idp_entity_id), logout_request.id)
elsif params[:SAMLResponse]
#Currently Devise handles the session invalidation when the request is made.
#To support a true SP initiated logout response, the request ID would have to be tracked and session invalidated
#based on that.
if Devise.saml_sign_out_success_url
redirect_to Devise.saml_sign_out_success_url
else
redirect_to action: :new
end
else
head :invalid_request
end
end
protected
# Override devise to send user to IdP logout for SLO
def after_sign_out_path_for(_)
request = OneLogin::RubySaml::Logoutrequest.new
request.create(saml_config)
end
def generate_idp_logout_response(saml_config, logout_request_id)
OneLogin::RubySaml::SloLogoutresponse.new.create(saml_config, logout_request_id, nil)
end
end
The Problem
When I manually save map the settings from my OneLogin adapter to my Company model (see screenshot), I'm able to authenticate as a user of my app using OneLogin as the identity provider (IdP). However now I need to provide a client with the XML metadata representing the app's setup. When I go to /saml/metadata.xml, I get the following configuration, which according to my client, is incorrect. The client didn't offer any further details about what the problem is. They are using PingFederate, if that matters.
<?xml version='1.0' encoding='UTF-8'?>
<md:EntityDescriptor ID='_a3581975-b73d-4784-a106-bafd61e15f87' xmlns:md='urn:oasis:names:tc:SAML:2.0:metadata'>
<md:SPSSODescriptor AuthnRequestsSigned='false' WantAssertionsSigned='false' protocolSupportEnumeration='urn:oasis:names:tc:SAML:2.0:protocol'>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
<md:AssertionConsumerService Binding='urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST' Location='https://mysubdomain.myapp.local:3000/saml/auth' index='0' isDefault='true'/>
</md:SPSSODescriptor>
</md:EntityDescriptor>
My question is, what am I doing wrong here and how can I correct it? As I said, I barely understand how SAML works under the hood.
There is no EntityID defined on that metadata XML.
If you try to verify the XML on a validation tool you will get
Line: 2 | Column: 0 --> Element
'{urn:oasis:names:tc:SAML:2.0:metadata}EntityDescriptor': The
attribute 'entityID' is required but missing.
If you review ruby-saml code, the EntityID is added to the metadata XML if a settings.issuer is defined. Can you verify if that data is provided? Maybe company.issuer that I see at IdPSettingsAdapter class has an empty value.

Mail Chimp & Rails Gibbon Gem - hostname does not match the server certificate

Just integrated the Gibbon, gem and I am getting a hostname does not match the server certificate error thrown back when trying to subscribe a new user?
def subscribe_to_mailchimp testing=false
return true if (Rails.env.test? && !testing)
list_id = ENV['My-list-id']
response = Rails.configuration.mailchimp.lists.subscribe({
id: list_id,
email: {email: email},
double_optin: false,
})
response
end
Slight change in the way that this works from the last time i looked seems to have fixed the issue.
Firstly
def subscribe_to_mailchimp testing=false
return true if (Rails.env.test? && !testing)
list_id = 'My-list-id'
response = Rails.configuration.mailchimp.lists.subscribe({
id: list_id,
email: {email: email},
double_optin: false,
})
response
end
Secondly
in config/initializers/mailchimp.rb
if Rails.env.test?
Gibbon::Export.api_key = "fake"
Gibbon::Export.throws_exceptions = false
end
Gibbon::API.api_key = "YOUR_API_KEY"
Gibbon::API.timeout = 15
Gibbon::API.throws_exceptions = false
Rails.configuration.mailchimp = Gibbon::API.new
Finally in application.rb
require 'openssl'
The Require openssl was what was generating the hostname does not match the server error as the call in the Gibbon app uses https
And if your interested in users.rb
def subscribe_to_mailchimp testing=false
return true if (Rails.env.test? && !testing)
list_id = "YOUR_LIST_ID"
response = Rails.configuration.mailchimp.lists.subscribe({
id: list_id,
email: {email: email},
double_optin: false,
})
response
end

How can I create an admin user on my live heroku app?

I tried going into the heroku console and adding a user with User.create(name: "admin", email: "admin#tradespring.net", admin: true). These are all valid columns in my user table and I have no problems creating an admin user locally (thought I do it differently. This is what it gives me.
irb(main):001:0> User.create(name: "admin", email:"admin#tradespring.net", admin: true)
WARNING: Can't mass-assign protected attributes: admin
(57.4ms) BEGIN
User Exists (12.4ms) SELECT 1 FROM "users" WHERE LOWER("users"."email") = LOWER('admin#tradespring.net') LIMIT 1
(30.3ms) ROLLBACK
=> #<User id: nil, name: "admin", email: "admin#tradespring.net", created_at: nil, updated_at: nil, password_digest: nil, remember_token: nil, admin: false>
clearly the admin setting didnt work as it is put as false. Also when I go to my site there is no new user named admin. I am not sure I am even taking the right steps though. What am I doing wrong/not doing?
User.create({name: "admin", email:"admin#tradespring.net", admin: true}, :without_protection => true)
An alternative would be to set the attributes one by one:
u = User.new
u.name = "admin"
u.email = "admin#tradespring.net"
u.admin = true
u.save!