Merge pull request #6010 from Anamika1608/saml
Add support for SAML authentication
This commit is contained in:
1
Gemfile
1
Gemfile
@@ -38,6 +38,7 @@ gem "omniauth", "~> 2.1.3"
|
|||||||
gem "omniauth-facebook", "~> 10.0.0"
|
gem "omniauth-facebook", "~> 10.0.0"
|
||||||
gem "omniauth-google-oauth2", "~> 1.2.1"
|
gem "omniauth-google-oauth2", "~> 1.2.1"
|
||||||
gem "omniauth-rails_csrf_protection", "~> 1.0.2"
|
gem "omniauth-rails_csrf_protection", "~> 1.0.2"
|
||||||
|
gem "omniauth-saml", "~> 2.2.4"
|
||||||
gem "omniauth-twitter", "~> 1.4.0"
|
gem "omniauth-twitter", "~> 1.4.0"
|
||||||
gem "paranoia", "~> 3.0.1"
|
gem "paranoia", "~> 3.0.1"
|
||||||
gem "pg", "~> 1.5.9"
|
gem "pg", "~> 1.5.9"
|
||||||
|
|||||||
@@ -440,6 +440,9 @@ GEM
|
|||||||
omniauth-rails_csrf_protection (1.0.2)
|
omniauth-rails_csrf_protection (1.0.2)
|
||||||
actionpack (>= 4.2)
|
actionpack (>= 4.2)
|
||||||
omniauth (~> 2.0)
|
omniauth (~> 2.0)
|
||||||
|
omniauth-saml (2.2.4)
|
||||||
|
omniauth (~> 2.1)
|
||||||
|
ruby-saml (~> 1.18)
|
||||||
omniauth-twitter (1.4.0)
|
omniauth-twitter (1.4.0)
|
||||||
omniauth-oauth (~> 1.1)
|
omniauth-oauth (~> 1.1)
|
||||||
rack
|
rack
|
||||||
@@ -609,6 +612,9 @@ GEM
|
|||||||
rubocop-rspec (~> 3, >= 3.0.1)
|
rubocop-rspec (~> 3, >= 3.0.1)
|
||||||
ruby-progressbar (1.13.0)
|
ruby-progressbar (1.13.0)
|
||||||
ruby-rc4 (0.1.5)
|
ruby-rc4 (0.1.5)
|
||||||
|
ruby-saml (1.18.0)
|
||||||
|
nokogiri (>= 1.13.10)
|
||||||
|
rexml
|
||||||
ruby-vips (2.2.3)
|
ruby-vips (2.2.3)
|
||||||
ffi (~> 1.12)
|
ffi (~> 1.12)
|
||||||
logger
|
logger
|
||||||
@@ -797,6 +803,7 @@ DEPENDENCIES
|
|||||||
omniauth-facebook (~> 10.0.0)
|
omniauth-facebook (~> 10.0.0)
|
||||||
omniauth-google-oauth2 (~> 1.2.1)
|
omniauth-google-oauth2 (~> 1.2.1)
|
||||||
omniauth-rails_csrf_protection (~> 1.0.2)
|
omniauth-rails_csrf_protection (~> 1.0.2)
|
||||||
|
omniauth-saml (~> 2.2.4)
|
||||||
omniauth-twitter (~> 1.4.0)
|
omniauth-twitter (~> 1.4.0)
|
||||||
paranoia (~> 3.0.1)
|
paranoia (~> 3.0.1)
|
||||||
pdf-reader (~> 2.14.1)
|
pdf-reader (~> 2.14.1)
|
||||||
|
|||||||
@@ -1392,7 +1392,8 @@ table {
|
|||||||
.button.button-twitter,
|
.button.button-twitter,
|
||||||
.button.button-facebook,
|
.button.button-facebook,
|
||||||
.button.button-google,
|
.button.button-google,
|
||||||
.button.button-wordpress {
|
.button.button-wordpress,
|
||||||
|
.button.button-saml {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|
||||||
@@ -1442,6 +1443,17 @@ table {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button.button-saml {
|
||||||
|
@include has-fa-icon(lock, solid);
|
||||||
|
background: #eafee9;
|
||||||
|
border-left: 3px solid #3b9857;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
color: #3b9857;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 14. Verification
|
// 14. Verification
|
||||||
// ----------------
|
// ----------------
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ class Admin::Settings::FeaturesTabComponent < ApplicationComponent
|
|||||||
feature.featured_proposals
|
feature.featured_proposals
|
||||||
feature.facebook_login
|
feature.facebook_login
|
||||||
feature.google_login
|
feature.google_login
|
||||||
|
feature.saml_login
|
||||||
feature.twitter_login
|
feature.twitter_login
|
||||||
feature.wordpress_login
|
feature.wordpress_login
|
||||||
feature.signature_sheets
|
feature.signature_sheets
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ class Devise::OmniauthFormComponent < ApplicationComponent
|
|||||||
(:twitter if feature?(:twitter_login)),
|
(:twitter if feature?(:twitter_login)),
|
||||||
(:facebook if feature?(:facebook_login)),
|
(:facebook if feature?(:facebook_login)),
|
||||||
(:google_oauth2 if feature?(:google_login)),
|
(:google_oauth2 if feature?(:google_login)),
|
||||||
(:wordpress_oauth2 if feature?(:wordpress_login))
|
(:wordpress_oauth2 if feature?(:wordpress_login)),
|
||||||
|
(:saml if feature?(:saml_login))
|
||||||
].compact
|
].compact
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
||||||
|
skip_before_action :verify_authenticity_token, only: :saml
|
||||||
|
|
||||||
def twitter
|
def twitter
|
||||||
sign_in_with :twitter_login, :twitter
|
sign_in_with :twitter_login, :twitter
|
||||||
end
|
end
|
||||||
@@ -15,6 +17,10 @@ class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
|||||||
sign_in_with :wordpress_login, :wordpress_oauth2
|
sign_in_with :wordpress_login, :wordpress_oauth2
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def saml
|
||||||
|
sign_in_with :saml_login, :saml
|
||||||
|
end
|
||||||
|
|
||||||
def after_sign_in_path_for(resource)
|
def after_sign_in_path_for(resource)
|
||||||
if resource.registering_with_oauth
|
if resource.registering_with_oauth
|
||||||
finish_signup_path
|
finish_signup_path
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ module OmniauthTenantSetup
|
|||||||
oauth2(env, secrets.wordpress_oauth2_key, secrets.wordpress_oauth2_secret)
|
oauth2(env, secrets.wordpress_oauth2_key, secrets.wordpress_oauth2_secret)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def saml(env)
|
||||||
|
saml_auth(env, secrets.saml_sp_entity_id,
|
||||||
|
secrets.saml_idp_metadata_url, secrets.saml_idp_sso_service_url)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def oauth(env, key, secret)
|
def oauth(env, key, secret)
|
||||||
@@ -32,6 +37,24 @@ module OmniauthTenantSetup
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def saml_auth(env, sp_entity_id, idp_metadata_url, idp_sso_service_url)
|
||||||
|
unless Tenant.default?
|
||||||
|
strategy = env["omniauth.strategy"]
|
||||||
|
|
||||||
|
strategy.options[:sp_entity_id] = sp_entity_id if sp_entity_id.present?
|
||||||
|
strategy.options[:idp_metadata_url] = idp_metadata_url if idp_metadata_url.present?
|
||||||
|
strategy.options[:idp_sso_service_url] = idp_sso_service_url if idp_sso_service_url.present?
|
||||||
|
|
||||||
|
if strategy.options[:issuer].present? && sp_entity_id.present?
|
||||||
|
strategy.options[:issuer] = sp_entity_id
|
||||||
|
end
|
||||||
|
|
||||||
|
if strategy.options[:idp_metadata].present? && idp_metadata_url.present?
|
||||||
|
strategy.options[:idp_metadata] = idp_metadata_url
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def secrets
|
def secrets
|
||||||
Tenant.current_secrets
|
Tenant.current_secrets
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ class Setting < ApplicationRecord
|
|||||||
"feature.remote_census": nil,
|
"feature.remote_census": nil,
|
||||||
"feature.valuation_comment_notification": true,
|
"feature.valuation_comment_notification": true,
|
||||||
"feature.graphql_api": true,
|
"feature.graphql_api": true,
|
||||||
|
"feature.saml_login": false,
|
||||||
"feature.sdg": true,
|
"feature.sdg": true,
|
||||||
"feature.machine_learning": false,
|
"feature.machine_learning": false,
|
||||||
"feature.remove_investments_supports": true,
|
"feature.remove_investments_supports": true,
|
||||||
|
|||||||
@@ -286,6 +286,15 @@ Devise.setup do |config|
|
|||||||
Rails.application.secrets.wordpress_oauth2_secret,
|
Rails.application.secrets.wordpress_oauth2_secret,
|
||||||
client_options: { site: Rails.application.secrets.wordpress_oauth2_site },
|
client_options: { site: Rails.application.secrets.wordpress_oauth2_site },
|
||||||
setup: ->(env) { OmniauthTenantSetup.wordpress_oauth2(env) }
|
setup: ->(env) { OmniauthTenantSetup.wordpress_oauth2(env) }
|
||||||
|
saml_settings = {}
|
||||||
|
if Rails.application.secrets.saml_idp_metadata_url.present?
|
||||||
|
idp_metadata_parser = OneLogin::RubySaml::IdpMetadataParser.new
|
||||||
|
saml_settings = idp_metadata_parser.parse_remote_to_hash(Rails.application.secrets.saml_idp_metadata_url)
|
||||||
|
saml_settings[:idp_sso_service_url] = Rails.application.secrets.saml_idp_sso_service_url
|
||||||
|
saml_settings[:sp_entity_id] = Rails.application.secrets.saml_sp_entity_id
|
||||||
|
saml_settings[:allowed_clock_drift] = 1.minute
|
||||||
|
end
|
||||||
|
config.omniauth :saml, saml_settings.merge(setup: ->(env) { OmniauthTenantSetup.saml(env) })
|
||||||
|
|
||||||
# ==> Warden configuration
|
# ==> Warden configuration
|
||||||
# If you want to use other strategies, that are not supported by Devise, or
|
# If you want to use other strategies, that are not supported by Devise, or
|
||||||
|
|||||||
@@ -278,6 +278,10 @@ en:
|
|||||||
info:
|
info:
|
||||||
sign_in: "Sign in with:"
|
sign_in: "Sign in with:"
|
||||||
sign_up: "Sign up with:"
|
sign_up: "Sign up with:"
|
||||||
|
saml:
|
||||||
|
sign_in: Sign in with SAML
|
||||||
|
sign_up: Sign up with SAML
|
||||||
|
name: SAML
|
||||||
or_fill: "Or fill the following form:"
|
or_fill: "Or fill the following form:"
|
||||||
proposals:
|
proposals:
|
||||||
create:
|
create:
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ en:
|
|||||||
google_login_description: "Allow users to sign up with their Google Account"
|
google_login_description: "Allow users to sign up with their Google Account"
|
||||||
wordpress_login: "Wordpress login"
|
wordpress_login: "Wordpress login"
|
||||||
wordpress_login_description: "Allow users to sign up with their Wordpress Account"
|
wordpress_login_description: "Allow users to sign up with their Wordpress Account"
|
||||||
|
saml_login: "SAML login"
|
||||||
|
saml_login_description: "Allow users to sign up with SAML"
|
||||||
featured_proposals: "Featured proposals"
|
featured_proposals: "Featured proposals"
|
||||||
featured_proposals_description: "Shows featured proposals on index proposals page"
|
featured_proposals_description: "Shows featured proposals on index proposals page"
|
||||||
signature_sheets: "Signature sheets"
|
signature_sheets: "Signature sheets"
|
||||||
|
|||||||
@@ -275,6 +275,10 @@ es:
|
|||||||
sign_in: Entra con Twitter
|
sign_in: Entra con Twitter
|
||||||
sign_up: Regístrate con Twitter
|
sign_up: Regístrate con Twitter
|
||||||
name: Twitter
|
name: Twitter
|
||||||
|
saml:
|
||||||
|
sign_in: Entra con SAML
|
||||||
|
sign_up: Regístrate con SAML
|
||||||
|
name: SAML
|
||||||
info:
|
info:
|
||||||
sign_in: "Entra con:"
|
sign_in: "Entra con:"
|
||||||
sign_up: "Regístrate con:"
|
sign_up: "Regístrate con:"
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ es:
|
|||||||
google_login_description: "Permitir que los usuarios se registren con su cuenta de Google"
|
google_login_description: "Permitir que los usuarios se registren con su cuenta de Google"
|
||||||
wordpress_login: "Registro con Wordpress"
|
wordpress_login: "Registro con Wordpress"
|
||||||
wordpress_login_description: "Permitir que los usuarios se registren con su cuenta de Wordpress"
|
wordpress_login_description: "Permitir que los usuarios se registren con su cuenta de Wordpress"
|
||||||
|
saml_login: "Registro con SAML"
|
||||||
|
saml_login_description: "Permitir que los usuarios se registren usando SAML"
|
||||||
featured_proposals: "Propuestas destacadas"
|
featured_proposals: "Propuestas destacadas"
|
||||||
featured_proposals_description: "Muestra propuestas destacadas en la página principal de propuestas"
|
featured_proposals_description: "Muestra propuestas destacadas en la página principal de propuestas"
|
||||||
signature_sheets: "Hojas de firmas"
|
signature_sheets: "Hojas de firmas"
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ staging:
|
|||||||
# secret_key: my_secret_value
|
# secret_key: my_secret_value
|
||||||
#
|
#
|
||||||
# Currently you can overwrite SMTP, SMS, manager, microsoft API,
|
# Currently you can overwrite SMTP, SMS, manager, microsoft API,
|
||||||
# HTTP basic, twitter, facebook, google, wordpress and security settings.
|
# HTTP basic, twitter, facebook, google, wordpress, SAML and security settings.
|
||||||
twitter_key: ""
|
twitter_key: ""
|
||||||
twitter_secret: ""
|
twitter_secret: ""
|
||||||
facebook_key: ""
|
facebook_key: ""
|
||||||
@@ -91,6 +91,9 @@ staging:
|
|||||||
wordpress_oauth2_key: ""
|
wordpress_oauth2_key: ""
|
||||||
wordpress_oauth2_secret: ""
|
wordpress_oauth2_secret: ""
|
||||||
wordpress_oauth2_site: ""
|
wordpress_oauth2_site: ""
|
||||||
|
saml_sp_entity_id: ""
|
||||||
|
saml_idp_metadata_url: ""
|
||||||
|
saml_idp_sso_service_url: ""
|
||||||
<<: *maps
|
<<: *maps
|
||||||
<<: *apis
|
<<: *apis
|
||||||
|
|
||||||
@@ -137,7 +140,7 @@ preproduction:
|
|||||||
# secret_key: my_secret_value
|
# secret_key: my_secret_value
|
||||||
#
|
#
|
||||||
# Currently you can overwrite SMTP, SMS, manager, microsoft API,
|
# Currently you can overwrite SMTP, SMS, manager, microsoft API,
|
||||||
# HTTP basic, twitter, facebook, google, wordpress and security settings.
|
# HTTP basic, twitter, facebook, google, wordpress, SAML and security settings.
|
||||||
twitter_key: ""
|
twitter_key: ""
|
||||||
twitter_secret: ""
|
twitter_secret: ""
|
||||||
facebook_key: ""
|
facebook_key: ""
|
||||||
@@ -147,6 +150,9 @@ preproduction:
|
|||||||
wordpress_oauth2_key: ""
|
wordpress_oauth2_key: ""
|
||||||
wordpress_oauth2_secret: ""
|
wordpress_oauth2_secret: ""
|
||||||
wordpress_oauth2_site: ""
|
wordpress_oauth2_site: ""
|
||||||
|
saml_sp_entity_id: ""
|
||||||
|
saml_idp_metadata_url: ""
|
||||||
|
saml_idp_sso_service_url: ""
|
||||||
<<: *maps
|
<<: *maps
|
||||||
<<: *apis
|
<<: *apis
|
||||||
|
|
||||||
@@ -192,7 +198,7 @@ production:
|
|||||||
# secret_key: my_secret_value
|
# secret_key: my_secret_value
|
||||||
#
|
#
|
||||||
# Currently you can overwrite SMTP, SMS, manager, microsoft API,
|
# Currently you can overwrite SMTP, SMS, manager, microsoft API,
|
||||||
# HTTP basic, twitter, facebook, google, wordpress and security settings.
|
# HTTP basic, twitter, facebook, google, wordpress, SAML and security settings.
|
||||||
twitter_key: ""
|
twitter_key: ""
|
||||||
twitter_secret: ""
|
twitter_secret: ""
|
||||||
facebook_key: ""
|
facebook_key: ""
|
||||||
@@ -202,5 +208,8 @@ production:
|
|||||||
wordpress_oauth2_key: ""
|
wordpress_oauth2_key: ""
|
||||||
wordpress_oauth2_secret: ""
|
wordpress_oauth2_secret: ""
|
||||||
wordpress_oauth2_site: ""
|
wordpress_oauth2_site: ""
|
||||||
|
saml_sp_entity_id: ""
|
||||||
|
saml_idp_metadata_url: ""
|
||||||
|
saml_idp_sso_service_url: ""
|
||||||
<<: *maps
|
<<: *maps
|
||||||
<<: *apis
|
<<: *apis
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
* [Tests](customization/tests.md)
|
* [Tests](customization/tests.md)
|
||||||
|
|
||||||
* [Technical Features](features/features.md)
|
* [Technical Features](features/features.md)
|
||||||
* [OAuth](features/oauth.md)
|
* [Authentication with external services (OAuth)](features/oauth.md)
|
||||||
* [GraphQL](features/graphql.md)
|
* [GraphQL](features/graphql.md)
|
||||||
* [Debates and proposals recommendations](features/recommendations.md)
|
* [Debates and proposals recommendations](features/recommendations.md)
|
||||||
* [Configure Census Connection](features/census_configuration.md)
|
* [Configure Census Connection](features/census_configuration.md)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# OAuth
|
# Authentication with external services (OAuth)
|
||||||
|
|
||||||
You can configure authentication services with external OAuth providers, right now Twitter, Facebook, Google and Wordpress are supported.
|
You can configure authentication services with external OAuth providers. Right now, Twitter, Facebook, Google, Wordpress and SAML are supported.
|
||||||
|
|
||||||
## 1. Create an App on the platform
|
## 1. Create an App on the platform
|
||||||
|
|
||||||
For each platform, go to their developers section and follow their guides to create an app.
|
For Twitter, Facebook, Google and Wordpress, go to their developers section and follow their guides to create an app. For SAML, you'll have to configure an Identity Provider (IdP).
|
||||||
|
|
||||||
## 2. Set the authentication URL of your Consul Democracy installation
|
## 2. Set the authentication URL of your Consul Democracy installation
|
||||||
|
|
||||||
@@ -15,10 +15,12 @@ They'll ask you for the authentication URL of your Consul Democracy installation
|
|||||||
user_twitter_omniauth_callback GET|POST /users/auth/twitter/callback(.:format) users/omniauth_callbacks#twitter
|
user_twitter_omniauth_callback GET|POST /users/auth/twitter/callback(.:format) users/omniauth_callbacks#twitter
|
||||||
user_facebook_omniauth_authorize GET|POST /users/auth/facebook(.:format) users/omniauth_callbacks#passthru
|
user_facebook_omniauth_authorize GET|POST /users/auth/facebook(.:format) users/omniauth_callbacks#passthru
|
||||||
user_facebook_omniauth_callback GET|POST /users/auth/facebook/callback(.:format) users/omniauth_callbacks#facebook
|
user_facebook_omniauth_callback GET|POST /users/auth/facebook/callback(.:format) users/omniauth_callbacks#facebook
|
||||||
user_google_oauth2_omniauth_authorize GET|POST /users/auth/google_oauth2(.:format) users omniauth_callbacks#passthru
|
user_google_oauth2_omniauth_authorize GET|POST /users/auth/google_oauth2(.:format) users/omniauth_callbacks#passthru
|
||||||
user_google_oauth2_omniauth_callback GET|POST /users/auth/google_oauth2/callback(.:format) users/omniauth_callbacks#google_oauth2
|
user_google_oauth2_omniauth_callback GET|POST /users/auth/google_oauth2/callback(.:format) users/omniauth_callbacks#google_oauth2
|
||||||
user_wordpress_oauth2_omniauth_authorize GET|POST /users/auth/wordpress_oauth2(.:format) users/omniauth_callbacks#passthru
|
user_wordpress_oauth2_omniauth_authorize GET|POST /users/auth/wordpress_oauth2(.:format) users/omniauth_callbacks#passthru
|
||||||
user_wordpress_oauth2_omniauth_callback GET|POST /users/auth/wordpress_oauth2/callback(.:format) users/omniauth_callbacks#wordpress_oauth2
|
user_wordpress_oauth2_omniauth_callback GET|POST /users/auth/wordpress_oauth2/callback(.:format) users/omniauth_callbacks#wordpress_oauth2
|
||||||
|
user_saml_omniauth_authorize GET|POST /users/auth/saml(.:format) users/omniauth_callbacks#passthru
|
||||||
|
user_saml_omniauth_callback GET|POST /users/auth/saml/callback(.:format) users/omniauth_callbacks#saml
|
||||||
```
|
```
|
||||||
|
|
||||||
So for example the URL for Facebook application would be `yourdomain.com/users/auth/facebook/callback`.
|
So for example the URL for Facebook application would be `yourdomain.com/users/auth/facebook/callback`.
|
||||||
@@ -37,4 +39,7 @@ When you complete the application registration you'll get a *key* and *secret* v
|
|||||||
wordpress_oauth2_key: ""
|
wordpress_oauth2_key: ""
|
||||||
wordpress_oauth2_secret: ""
|
wordpress_oauth2_secret: ""
|
||||||
wordpress_oauth2_site: ""
|
wordpress_oauth2_site: ""
|
||||||
|
saml_sp_entity_id: "https://yoursp.org/entityid"
|
||||||
|
saml_idp_metadata_url: "https://youridp.org/api/saml/metadata"
|
||||||
|
saml_idp_sso_service_url: "https://youridp.org/api/saml/sso"
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
* [Tests](customization/tests.md)
|
* [Tests](customization/tests.md)
|
||||||
|
|
||||||
* [Funcionalidades Técnicas](features/features.md)
|
* [Funcionalidades Técnicas](features/features.md)
|
||||||
* [OAuth](features/oauth.md)
|
* [Autenticación con servicios externos (OAuth)](features/oauth.md)
|
||||||
* [GraphQL](features/graphql.md)
|
* [GraphQL](features/graphql.md)
|
||||||
* [Recomendaciones de debates y propuestas](features/recommendations.md)
|
* [Recomendaciones de debates y propuestas](features/recommendations.md)
|
||||||
* [Configurar conexión con el Censo](features/census_configuration.md)
|
* [Configurar conexión con el Censo](features/census_configuration.md)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# OAuth
|
# Autenticación con servicios externos (OAuth)
|
||||||
|
|
||||||
Puedes configurar la autenticación con servicios externos usando OAuth, actualmente se pueden utilizar Twitter, Facebook, Google y Wordpress.
|
Puedes configurar la autenticación con servicios externos usando OAuth. Actualmente, se pueden utilizar Twitter, Facebook, Google, Wordpress y SAML.
|
||||||
|
|
||||||
## 1. Crea una aplicación en la plataforma
|
## 1. Crea una aplicación en la plataforma
|
||||||
|
|
||||||
Para cada plataforma, sigue las instrucciones en la sección de desarrolladores de su página web.
|
Para Twitter, Facebook, Google y Wordpress, sigue las instrucciones en la sección de desarrolladores de su página web. Para SAML, tendrás que configurar tu propio proveedor de identidad (IdP).
|
||||||
|
|
||||||
## 2. Establece la URL de autenticación de tu instalación de Consul Democracy
|
## 2. Establece la URL de autenticación de tu instalación de Consul Democracy
|
||||||
|
|
||||||
@@ -15,10 +15,12 @@ Te preguntarán por la URL de autenticación de tu instalación de Consul Democr
|
|||||||
user_twitter_omniauth_callback GET|POST /users/auth/twitter/callback(.:format) users/omniauth_callbacks#twitter
|
user_twitter_omniauth_callback GET|POST /users/auth/twitter/callback(.:format) users/omniauth_callbacks#twitter
|
||||||
user_facebook_omniauth_authorize GET|POST /users/auth/facebook(.:format) users/omniauth_callbacks#passthru
|
user_facebook_omniauth_authorize GET|POST /users/auth/facebook(.:format) users/omniauth_callbacks#passthru
|
||||||
user_facebook_omniauth_callback GET|POST /users/auth/facebook/callback(.:format) users/omniauth_callbacks#facebook
|
user_facebook_omniauth_callback GET|POST /users/auth/facebook/callback(.:format) users/omniauth_callbacks#facebook
|
||||||
user_google_oauth2_omniauth_authorize GET|POST /users/auth/google_oauth2(.:format) users omniauth_callbacks#passthru
|
user_google_oauth2_omniauth_authorize GET|POST /users/auth/google_oauth2(.:format) users/omniauth_callbacks#passthru
|
||||||
user_google_oauth2_omniauth_callback GET|POST /users/auth/google_oauth2/callback(.:format) users/omniauth_callbacks#google_oauth2
|
user_google_oauth2_omniauth_callback GET|POST /users/auth/google_oauth2/callback(.:format) users/omniauth_callbacks#google_oauth2
|
||||||
user_wordpress_oauth2_omniauth_authorize GET|POST /users/auth/wordpress_oauth2(.:format) users/omniauth_callbacks#passthru
|
user_wordpress_oauth2_omniauth_authorize GET|POST /users/auth/wordpress_oauth2(.:format) users/omniauth_callbacks#passthru
|
||||||
user_wordpress_oauth2_omniauth_callback GET|POST /users/auth/wordpress_oauth2/callback(.:format) users/omniauth_callbacks#wordpress_oauth2
|
user_wordpress_oauth2_omniauth_callback GET|POST /users/auth/wordpress_oauth2/callback(.:format) users/omniauth_callbacks#wordpress_oauth2
|
||||||
|
user_saml_omniauth_authorize GET|POST /users/auth/saml(.:format) users/omniauth_callbacks#passthru
|
||||||
|
user_saml_omniauth_callback GET|POST /users/auth/saml/callback(.:format) users/omniauth_callbacks#saml
|
||||||
```
|
```
|
||||||
|
|
||||||
Por ejemplo para Facebook la URL sería `yourdomain.com/users/auth/facebook/callback`.
|
Por ejemplo para Facebook la URL sería `yourdomain.com/users/auth/facebook/callback`.
|
||||||
@@ -37,4 +39,7 @@ Cuando completes el registro de la aplicación en su plataforma te darán un *ke
|
|||||||
wordpress_oauth2_key: ""
|
wordpress_oauth2_key: ""
|
||||||
wordpress_oauth2_secret: ""
|
wordpress_oauth2_secret: ""
|
||||||
wordpress_oauth2_site: ""
|
wordpress_oauth2_site: ""
|
||||||
|
saml_sp_entity_id: "https://tusp.org/entityid"
|
||||||
|
saml_idp_metadata_url: "https://tuidp.org/api/saml/metadata"
|
||||||
|
saml_idp_sso_service_url: "https://tuidp.org/api/saml/sso"
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ describe Devise::OmniauthFormComponent do
|
|||||||
Setting["feature.twitter_login"] = false
|
Setting["feature.twitter_login"] = false
|
||||||
Setting["feature.google_login"] = false
|
Setting["feature.google_login"] = false
|
||||||
Setting["feature.wordpress_login"] = false
|
Setting["feature.wordpress_login"] = false
|
||||||
|
Setting["feature.saml_login"] = false
|
||||||
end
|
end
|
||||||
|
|
||||||
it "is not rendered when all authentications are disabled" do
|
it "is not rendered when all authentications are disabled" do
|
||||||
@@ -52,5 +53,14 @@ describe Devise::OmniauthFormComponent do
|
|||||||
expect(page).to have_button "Wordpress"
|
expect(page).to have_button "Wordpress"
|
||||||
expect(page).to have_button count: 1
|
expect(page).to have_button count: 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "renders the SAML link when the feature is enabled" do
|
||||||
|
Setting["feature.saml_login"] = true
|
||||||
|
|
||||||
|
render_inline component
|
||||||
|
|
||||||
|
expect(page).to have_button "SAML"
|
||||||
|
expect(page).to have_button count: 1
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
87
spec/lib/omniauth_tenant_setup_spec.rb
Normal file
87
spec/lib/omniauth_tenant_setup_spec.rb
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
require "rails_helper"
|
||||||
|
|
||||||
|
describe OmniauthTenantSetup do
|
||||||
|
describe "#saml" do
|
||||||
|
it "uses different secrets for different tenants" do
|
||||||
|
create(:tenant, schema: "mars")
|
||||||
|
create(:tenant, schema: "venus")
|
||||||
|
|
||||||
|
stub_secrets(
|
||||||
|
saml_sp_entity_id: "https://default.consul.dev/saml/metadata",
|
||||||
|
saml_idp_metadata_url: "https://default-idp.example.com/metadata",
|
||||||
|
saml_idp_sso_service_url: "https://default-idp.example.com/sso",
|
||||||
|
tenants: {
|
||||||
|
mars: {
|
||||||
|
saml_sp_entity_id: "https://mars.consul.dev/saml/metadata",
|
||||||
|
saml_idp_metadata_url: "https://mars-idp.example.com/metadata",
|
||||||
|
saml_idp_sso_service_url: "https://mars-idp.example.com/sso"
|
||||||
|
},
|
||||||
|
venus: {
|
||||||
|
saml_sp_entity_id: "https://venus.consul.dev/saml/metadata",
|
||||||
|
saml_idp_metadata_url: "https://venus-idp.example.com/metadata",
|
||||||
|
saml_idp_sso_service_url: "https://venus-idp.example.com/sso"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Tenant.switch("mars") do
|
||||||
|
mars_env = {
|
||||||
|
"omniauth.strategy" => double(options: {}),
|
||||||
|
"HTTP_HOST" => "mars.consul.dev"
|
||||||
|
}
|
||||||
|
|
||||||
|
OmniauthTenantSetup.saml(mars_env)
|
||||||
|
mars_strategy_options = mars_env["omniauth.strategy"].options
|
||||||
|
|
||||||
|
expect(mars_strategy_options[:sp_entity_id]).to eq "https://mars.consul.dev/saml/metadata"
|
||||||
|
expect(mars_strategy_options[:idp_metadata_url]).to eq "https://mars-idp.example.com/metadata"
|
||||||
|
expect(mars_strategy_options[:idp_sso_service_url]).to eq "https://mars-idp.example.com/sso"
|
||||||
|
end
|
||||||
|
|
||||||
|
Tenant.switch("venus") do
|
||||||
|
venus_env = {
|
||||||
|
"omniauth.strategy" => double(options: {}),
|
||||||
|
"HTTP_HOST" => "venus.consul.dev"
|
||||||
|
}
|
||||||
|
|
||||||
|
OmniauthTenantSetup.saml(venus_env)
|
||||||
|
venus_strategy_options = venus_env["omniauth.strategy"].options
|
||||||
|
|
||||||
|
expect(venus_strategy_options[:sp_entity_id]).to eq "https://venus.consul.dev/saml/metadata"
|
||||||
|
expect(venus_strategy_options[:idp_metadata_url]).to eq "https://venus-idp.example.com/metadata"
|
||||||
|
expect(venus_strategy_options[:idp_sso_service_url]).to eq "https://venus-idp.example.com/sso"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "uses default secrets for non-overridden tenant" do
|
||||||
|
create(:tenant, schema: "earth")
|
||||||
|
|
||||||
|
stub_secrets(
|
||||||
|
saml_sp_entity_id: "https://default.consul.dev/saml/metadata",
|
||||||
|
saml_idp_metadata_url: "https://default-idp.example.com/metadata",
|
||||||
|
saml_idp_sso_service_url: "https://default-idp.example.com/sso",
|
||||||
|
tenants: {
|
||||||
|
mars: {
|
||||||
|
saml_sp_entity_id: "https://mars.consul.dev/saml/metadata",
|
||||||
|
saml_idp_metadata_url: "https://mars-idp.example.com/metadata",
|
||||||
|
saml_idp_sso_service_url: "https://mars-idp.example.com/sso"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Tenant.switch("earth") do
|
||||||
|
earth_env = {
|
||||||
|
"omniauth.strategy" => double(options: {}),
|
||||||
|
"HTTP_HOST" => "earth.consul.dev"
|
||||||
|
}
|
||||||
|
|
||||||
|
OmniauthTenantSetup.saml(earth_env)
|
||||||
|
earth_strategy_options = earth_env["omniauth.strategy"].options
|
||||||
|
|
||||||
|
expect(earth_strategy_options[:sp_entity_id]).to eq "https://default.consul.dev/saml/metadata"
|
||||||
|
expect(earth_strategy_options[:idp_metadata_url]).to eq "https://default-idp.example.com/metadata"
|
||||||
|
expect(earth_strategy_options[:idp_sso_service_url]).to eq "https://default-idp.example.com/sso"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -488,6 +488,163 @@ describe "Users" do
|
|||||||
expect(page).to have_field "Email", with: "manuela@consul.dev"
|
expect(page).to have_field "Email", with: "manuela@consul.dev"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "Saml" do
|
||||||
|
before { Setting["feature.saml_login"] = true }
|
||||||
|
|
||||||
|
let(:saml_hash_with_email) do
|
||||||
|
{
|
||||||
|
provider: "saml",
|
||||||
|
uid: "ext-tester",
|
||||||
|
info: {
|
||||||
|
name: "samltester",
|
||||||
|
email: "tester@consul.dev"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:saml_hash_with_verified_email) do
|
||||||
|
{
|
||||||
|
provider: "saml",
|
||||||
|
uid: "ext-tester",
|
||||||
|
info: {
|
||||||
|
name: "samltester",
|
||||||
|
email: "tester@consul.dev",
|
||||||
|
verified: "1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Sign up with a confirmed email" do
|
||||||
|
OmniAuth.config.add_mock(:saml, saml_hash_with_verified_email)
|
||||||
|
|
||||||
|
visit new_user_registration_path
|
||||||
|
click_button "Sign up with SAML"
|
||||||
|
|
||||||
|
expect(page).to have_content "Successfully identified as Saml"
|
||||||
|
expect_to_be_signed_in
|
||||||
|
|
||||||
|
within("#notice") { click_button "Close" }
|
||||||
|
click_link "My account"
|
||||||
|
|
||||||
|
expect(page).to have_field "Username", with: "samltester"
|
||||||
|
|
||||||
|
click_link "Change my login details"
|
||||||
|
|
||||||
|
expect(page).to have_field "Email", with: "tester@consul.dev"
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Sign up with an unconfirmed email" do
|
||||||
|
OmniAuth.config.add_mock(:saml, saml_hash_with_email)
|
||||||
|
|
||||||
|
visit new_user_registration_path
|
||||||
|
click_button "Sign up with SAML"
|
||||||
|
|
||||||
|
expect(page).to have_content "To continue, please click on the confirmation " \
|
||||||
|
"link that we have sent you via email"
|
||||||
|
|
||||||
|
confirm_email
|
||||||
|
expect(page).to have_content "Your account has been confirmed"
|
||||||
|
expect(page).to have_current_path new_user_session_path
|
||||||
|
|
||||||
|
click_button "Sign in with SAML"
|
||||||
|
|
||||||
|
expect(page).to have_content "Successfully identified as Saml"
|
||||||
|
expect_to_be_signed_in
|
||||||
|
|
||||||
|
within("#notice") { click_button "Close" }
|
||||||
|
click_link "My account"
|
||||||
|
|
||||||
|
expect(page).to have_field "Username", with: "samltester"
|
||||||
|
|
||||||
|
click_link "Change my login details"
|
||||||
|
|
||||||
|
expect(page).to have_field "Email", with: "tester@consul.dev"
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Sign in with a user with a SAML identity" do
|
||||||
|
user = create(:user, username: "samltester", email: "tester@consul.dev", password: "My123456")
|
||||||
|
create(:identity, uid: "ext-tester", provider: "saml", user: user)
|
||||||
|
OmniAuth.config.add_mock(:saml, { provider: "saml", uid: "ext-tester" })
|
||||||
|
|
||||||
|
visit new_user_session_path
|
||||||
|
click_button "Sign in with SAML"
|
||||||
|
|
||||||
|
expect(page).to have_content "Successfully identified as Saml"
|
||||||
|
expect_to_be_signed_in
|
||||||
|
|
||||||
|
within("#notice") { click_button "Close" }
|
||||||
|
click_link "My account"
|
||||||
|
|
||||||
|
expect(page).to have_field "Username", with: "samltester"
|
||||||
|
|
||||||
|
click_link "Change my login details"
|
||||||
|
|
||||||
|
expect(page).to have_field "Email", with: "tester@consul.dev"
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Sign in with a user without a SAML identity keeps the username" do
|
||||||
|
create(:user, username: "tester", email: "tester@consul.dev", password: "My123456")
|
||||||
|
OmniAuth.config.add_mock(:saml, saml_hash_with_verified_email)
|
||||||
|
|
||||||
|
visit new_user_session_path
|
||||||
|
click_button "Sign in with SAML"
|
||||||
|
|
||||||
|
expect(page).to have_content "Successfully identified as Saml"
|
||||||
|
expect_to_be_signed_in
|
||||||
|
|
||||||
|
within("#notice") { click_button "Close" }
|
||||||
|
click_link "My account"
|
||||||
|
|
||||||
|
expect(page).to have_field "Username", with: "tester"
|
||||||
|
|
||||||
|
click_link "Change my login details"
|
||||||
|
|
||||||
|
expect(page).to have_field "Email", with: "tester@consul.dev"
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "SAML user from one tenant cannot sign in to another tenant", :seed_tenants do
|
||||||
|
%w[mars venus].each do |schema|
|
||||||
|
create(:tenant, schema: schema)
|
||||||
|
Tenant.switch(schema) { Setting["feature.saml_login"] = true }
|
||||||
|
end
|
||||||
|
|
||||||
|
Tenant.switch("mars") do
|
||||||
|
mars_user = create(:user, username: "marsuser", email: "mars@consul.dev")
|
||||||
|
create(:identity, uid: "mars-saml-123", provider: "saml", user: mars_user)
|
||||||
|
end
|
||||||
|
|
||||||
|
mars_saml_hash = {
|
||||||
|
provider: "saml",
|
||||||
|
uid: "mars-saml-123",
|
||||||
|
info: {
|
||||||
|
name: "marsuser",
|
||||||
|
email: "mars@consul.dev"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OmniAuth.config.add_mock(:saml, mars_saml_hash)
|
||||||
|
|
||||||
|
with_subdomain("mars") do
|
||||||
|
visit new_user_session_path
|
||||||
|
click_button "Sign in with SAML"
|
||||||
|
|
||||||
|
expect(page).to have_content "Successfully identified as Saml"
|
||||||
|
|
||||||
|
within("#notice") { click_button "Close" }
|
||||||
|
click_link "My account"
|
||||||
|
|
||||||
|
expect(page).to have_field "Username", with: "marsuser"
|
||||||
|
end
|
||||||
|
|
||||||
|
with_subdomain("venus") do
|
||||||
|
visit new_user_session_path
|
||||||
|
click_button "Sign in with SAML"
|
||||||
|
|
||||||
|
expect(page).to have_content "To continue, please click on the confirmation " \
|
||||||
|
"link that we have sent you via email"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario "Sign out" do
|
scenario "Sign out" do
|
||||||
|
|||||||
Reference in New Issue
Block a user