mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-27 06:05:19 +00:00
Configure OIDC
This commit is contained in:
committed by
Maikel Linke
parent
b36fae1bbb
commit
617164684c
@@ -6,3 +6,6 @@ STRIPE_SECRET_TEST_API_KEY="bogus_key"
|
||||
STRIPE_CUSTOMER="bogus_customer"
|
||||
|
||||
SITE_URL="test.host"
|
||||
|
||||
OPENID_APP_ID="test-provider"
|
||||
OPENID_APP_SECRET="12345"
|
||||
|
||||
7
app/controllers/admin/oidc_settings_controller.rb
Normal file
7
app/controllers/admin/oidc_settings_controller.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Admin
|
||||
class OidcSettingsController < Spree::Admin::BaseController
|
||||
def index; end
|
||||
end
|
||||
end
|
||||
16
app/controllers/omniauth_callbacks_controller.rb
Normal file
16
app/controllers/omniauth_callbacks_controller.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
||||
def openid_connect
|
||||
spree_current_user.link_from_omniauth(request.env["omniauth.auth"])
|
||||
|
||||
redirect_to admin_oidc_settings_path
|
||||
end
|
||||
|
||||
def failure
|
||||
error_message = request.env["omniauth.error"].to_s
|
||||
flash[:error] = t("devise.oidc.failure", error: error_message)
|
||||
|
||||
super
|
||||
end
|
||||
end
|
||||
@@ -7,8 +7,10 @@ module Spree
|
||||
searchable_attributes :email
|
||||
|
||||
devise :database_authenticatable, :token_authenticatable, :registerable, :recoverable,
|
||||
:rememberable, :trackable, :validatable,
|
||||
:encryptable, :confirmable, encryptor: 'authlogic_sha512', reconfirmable: true
|
||||
:rememberable, :trackable, :validatable, :omniauthable,
|
||||
:encryptable, :confirmable,
|
||||
encryptor: 'authlogic_sha512', reconfirmable: true,
|
||||
omniauth_providers: [:openid_connect]
|
||||
|
||||
has_many :orders
|
||||
belongs_to :ship_address, class_name: 'Spree::Address'
|
||||
@@ -44,6 +46,8 @@ module Spree
|
||||
after_create :associate_customers, :associate_orders
|
||||
|
||||
validate :limit_owned_enterprises
|
||||
validates :uid, uniqueness: true, if: lambda { uid.present? }
|
||||
validates_email :uid, if: lambda { uid.present? }
|
||||
|
||||
class DestroyWithOrdersError < StandardError; end
|
||||
|
||||
@@ -51,6 +55,10 @@ module Spree
|
||||
User.admin.count > 0
|
||||
end
|
||||
|
||||
def link_from_omniauth(auth)
|
||||
update!(provider: auth.provider, uid: auth.uid)
|
||||
end
|
||||
|
||||
# Whether a user has a role or not.
|
||||
def has_spree_role?(role_in_question)
|
||||
spree_roles.where(name: role_in_question.to_s).any?
|
||||
|
||||
25
app/views/admin/oidc_settings/index.html.haml
Normal file
25
app/views/admin/oidc_settings/index.html.haml
Normal file
@@ -0,0 +1,25 @@
|
||||
- content_for :page_title do
|
||||
= t(".title")
|
||||
|
||||
= render 'admin/shared/enterprises_sub_menu'
|
||||
|
||||
%div
|
||||
%h2= t(".connect")
|
||||
%br
|
||||
|
||||
- if spree_current_user.provider == 'openid_connect' && spree_current_user.uid.present?
|
||||
= t(".already_connected")
|
||||
= spree_current_user.uid
|
||||
%br
|
||||
%br
|
||||
|
||||
= t(".view_account")
|
||||
= link_to t(".les_communs_link"), "#{ Devise.omniauth_configs[:openid_connect].options[:issuer] }/account"
|
||||
|
||||
- else
|
||||
= t(".link_your_account")
|
||||
%br
|
||||
%br
|
||||
= button_to t(".link_account_button"),
|
||||
Spree::Core::Engine.routes.url_helpers.spree_user_openid_connect_omniauth_authorize_path(auth_type: "login"),
|
||||
method: :post
|
||||
@@ -2,3 +2,5 @@
|
||||
%ul#sub_nav.inline-menu{"data-hook" => "admin_enterprise_sub_tabs"}
|
||||
= tab :enterprises, url: main_app.admin_enterprises_path
|
||||
= tab :enterprise_relationships, url: main_app.admin_enterprise_relationships_path
|
||||
- if ENV["OPENID_APP_ID"].present? && ENV["OPENID_APP_SECRET"].present?
|
||||
= tab :oidc_settings, url: main_app.admin_oidc_settings_path
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
= tab :orders, :subscriptions, :customer_details, :adjustments, :payments, :return_authorizations, url: admin_orders_path('q[s]' => 'completed_at desc'), icon: 'icon-shopping-cart'
|
||||
= tab :reports, url: main_app.admin_reports_path, icon: 'icon-file'
|
||||
= tab :general_settings, :mail_methods, :tax_categories, :tax_rates, :tax_settings, :zones, :countries, :states, :payment_methods, :taxonomies, :shipping_methods, :shipping_categories, :enterprise_fees, :contents, :invoice_settings, :matomo_settings, :stripe_connect_settings, label: 'configuration', icon: 'icon-wrench', url: edit_admin_general_settings_path
|
||||
= tab :enterprises, :enterprise_relationships, url: main_app.admin_enterprises_path
|
||||
= tab :enterprises, :enterprise_relationships, :oidc_settings, url: main_app.admin_enterprises_path
|
||||
= tab :customers, url: main_app.admin_customers_path
|
||||
= tab :enterprise_groups, url: main_app.admin_enterprise_groups_path, label: 'groups'
|
||||
- if can? :admin, Spree::User
|
||||
|
||||
@@ -142,3 +142,25 @@ Devise::TokenAuthenticatable.setup do |config|
|
||||
# Defines name of the authentication token params key
|
||||
config.token_authentication_key = :auth_token
|
||||
end
|
||||
|
||||
if ENV["OPENID_APP_ID"].present? && ENV["OPENID_APP_SECRET"].present?
|
||||
Devise.setup do |config|
|
||||
protocol = Rails.env.development? ? "http://" : "https://"
|
||||
config.omniauth :openid_connect, {
|
||||
name: :openid_connect,
|
||||
issuer: "https://login.lescommuns.org/auth/realms/data-food-consortium",
|
||||
scope: [:openid, :profile, :email],
|
||||
response_type: :code,
|
||||
uid_field: "email",
|
||||
discovery: true,
|
||||
client_auth_method: :jwks,
|
||||
|
||||
client_options: {
|
||||
identifier: ENV["OPENID_APP_ID"],
|
||||
secret: ENV["OPENID_APP_SECRET"],
|
||||
redirect_uri: "#{protocol}#{ENV["SITE_URL"]}/user/spree_user/auth/openid_connect/callback",
|
||||
jwks_uri: 'https://login.lescommuns.org/auth/realms/data-food-consortium/protocol/openid-connect/certs'
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -224,7 +224,8 @@ en:
|
||||
updated_not_active: "Your password has been reset, but your email has not been confirmed yet."
|
||||
updated: "Your password was changed successfully. You are now signed in."
|
||||
send_instructions: "You will receive an email with instructions about how to confirm your account in a few minutes."
|
||||
|
||||
oidc:
|
||||
failure: "Could not sign in: %{error}"
|
||||
home_page_alert_html: "Home page alert HTML"
|
||||
hub_signup_case_studies_html: "Hub signup case studies HTML"
|
||||
hub_signup_detail_html: "Hub signup detail HTML"
|
||||
@@ -1423,6 +1424,15 @@ en:
|
||||
formatted_data: Formatted Data
|
||||
packing:
|
||||
name: "Packing Reports"
|
||||
oidc_settings:
|
||||
index:
|
||||
title: "OIDC Settings"
|
||||
connect: "Connect Your Account"
|
||||
already_connected: "Your account is already linked to this DFC authorization account:"
|
||||
les_communs_link: "Les Communs Open ID server"
|
||||
link_your_account: "You need first to link your account with the authorization provider used by DFC (Les Communs Open ID Connect)."
|
||||
link_account_button: "Link your Les Communs OIDC Account"
|
||||
view_account: "To view your account, see:"
|
||||
subscriptions:
|
||||
index:
|
||||
title: "Subscriptions"
|
||||
|
||||
@@ -107,6 +107,8 @@ Openfoodnetwork::Application.routes.draw do
|
||||
put :unpause, on: :member
|
||||
end
|
||||
|
||||
resources :oidc_settings, only: :index
|
||||
|
||||
resources :subscription_line_items, only: [], format: :json do
|
||||
post :build, on: :collection
|
||||
end
|
||||
|
||||
@@ -9,12 +9,14 @@ end
|
||||
# Overriding Devise routes to use our own controller
|
||||
Spree::Core::Engine.routes.draw do
|
||||
devise_for :spree_user,
|
||||
:router_name => "spree",
|
||||
:class_name => 'Spree::User',
|
||||
:controllers => { :sessions => 'spree/user_sessions',
|
||||
:registrations => 'user_registrations',
|
||||
:passwords => 'user_passwords',
|
||||
:confirmations => 'user_confirmations'},
|
||||
:skip => [:unlocks, :omniauth_callbacks],
|
||||
:confirmations => 'user_confirmations',
|
||||
:omniauth_callbacks => "omniauth_callbacks" },
|
||||
:skip => [:unlocks],
|
||||
:path_names => { :sign_out => 'logout' },
|
||||
:path_prefix => :user
|
||||
|
||||
|
||||
@@ -240,4 +240,18 @@ describe Spree::User do
|
||||
expect(user.disabled).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
describe "#link_from_omniauth" do
|
||||
let!(:user) { create(:user, email: "user@email.com") }
|
||||
let(:auth) { double(:auth, provider: "openid_connect", uid: "user@email.com") }
|
||||
|
||||
it "creates a user without errors" do
|
||||
user.link_from_omniauth(auth)
|
||||
|
||||
expect(user.errors.present?).to be false
|
||||
expect(user.confirmed?).to be true
|
||||
expect(user.provider).to eq "openid_connect"
|
||||
expect(user.uid).to eq "user@email.com"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
57
spec/requests/omniauth_callbacks_controller_spec.rb
Normal file
57
spec/requests/omniauth_callbacks_controller_spec.rb
Normal file
@@ -0,0 +1,57 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe OmniauthCallbacksController, type: :request do
|
||||
include AuthenticationHelper
|
||||
|
||||
OmniAuth.config.test_mode = true
|
||||
|
||||
subject do
|
||||
login_as user
|
||||
post '/user/spree_user/auth/openid_connect/callback', params: { code: 'code123' }
|
||||
|
||||
request.env['devise.mapping'] = Devise.mappings[:spree_user]
|
||||
request.env['omniauth.auth'] = omniauth_response
|
||||
end
|
||||
|
||||
let(:user) { create(:user) }
|
||||
|
||||
context 'when the omniauth setup is returning with an authorization' do
|
||||
let!(:omniauth_response) do
|
||||
OmniAuth.config.mock_auth[:openid_connect] = OmniAuth::AuthHash.new(
|
||||
'provider' => 'openid_connect',
|
||||
'uid' => 'john@doe.com',
|
||||
'info' => {
|
||||
'email' => 'john@doe.com',
|
||||
'first_name' => 'John',
|
||||
'last_name' => 'Doe'
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'is successful' do
|
||||
subject
|
||||
|
||||
expect(user.provider).to eq "openid_connect"
|
||||
expect(user.uid).to eq "john@doe.com"
|
||||
expect(request.cookies[:omniauth_connect]).to be_nil
|
||||
expect(response.status).to eq(302)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the omniauth openid_connect is mocked with an error' do
|
||||
let!(:omniauth_response) do
|
||||
OmniAuth.config.mock_auth[:openid_connect] = :invalid_credentials
|
||||
end
|
||||
|
||||
it 'fails with bad auth data' do
|
||||
subject
|
||||
|
||||
expect(user.provider).to be_nil
|
||||
expect(user.uid).to be_nil
|
||||
expect(request.cookies[:omniauth_connect]).to be_nil
|
||||
expect(response.status).to eq(302)
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user