-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Osso #1
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
module Authentication | ||
module Providers | ||
# Osso authentication provider, uses omniauth-osso as backend. | ||
# Osso is an open source service for adding SAML based SSO to | ||
# your application. The Osso team added Osso as a provider | ||
# in order to serve as a real-world example of how simple it | ||
# is to integrate Osso. | ||
# | ||
# Learn more about Osso at https://ossoapp.com | ||
|
||
class Osso < Provider | ||
OFFICIAL_NAME = "SAML SSO".freeze | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd probably want to use ENV vars here if I were actually adding this to forem. if its an internal community, it might be "Sign in with EnterpriseCo Okta". but in multi-tenancy, we expect folks to be more generic and not use "Osso". |
||
SETTINGS_URL = "https://ossoapp.com".freeze # TODO | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this can read off ENV to send to admin ui |
||
|
||
def new_user_data | ||
name = info.name || info.email.to_s | ||
|
||
{ | ||
email: info.email.to_s, | ||
name: name, | ||
osso_username: user_nickname | ||
} | ||
end | ||
|
||
def existing_user_data | ||
{ | ||
email: info.email.to_s | ||
} | ||
end | ||
|
||
def user_email | ||
info.email.to_s | ||
end | ||
|
||
# We're overriding this method because Osso doesn't have a concept nickname or username. | ||
# Instead: we'll construct one based on the user's name with some randomization thrown in based | ||
# on uid, which is guaranteed to be present and unique on Facebook. | ||
def user_nickname | ||
[ | ||
info.name.sub(" ", "_"), | ||
Digest::SHA512.hexdigest(payload.uid), | ||
].join("_")[0...25] | ||
end | ||
|
||
def self.official_name | ||
OFFICIAL_NAME | ||
end | ||
|
||
def self.settings_url | ||
SETTINGS_URL | ||
end | ||
|
||
# We're overriding these methods to add a little security with a random | ||
# string for state | ||
def self.authentication_path(state: SecureRandom.hex(32), **kwargs) | ||
::Authentication::Paths.authentication_path( | ||
provider_name, | ||
state: state, | ||
**kwargs, | ||
) | ||
end | ||
|
||
# TODO: this suggests we can pass email in, rather than use hosted login | ||
def self.sign_in_path(state: SecureRandom.hex(32), **_kwargs) | ||
::Authentication::Paths.authentication_path( | ||
provider_name, | ||
email: "[email protected]", | ||
state: state, | ||
) | ||
end | ||
|
||
protected | ||
|
||
def cleanup_payload(auth_payload) | ||
auth_payload | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
class AddOssoLoginFields < ActiveRecord::Migration[6.0] | ||
def change | ||
add_column :users, :osso_username, :string | ||
add_column :users, :osso_created_at, :datetime | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
require "rails_helper" | ||
|
||
RSpec.describe Authentication::Providers::Osso, type: :service do | ||
describe ".authentication_path" do | ||
it "returns the correct authentication path" do | ||
expected_path = Rails.application.routes.url_helpers.user_osso_omniauth_authorize_path | ||
expect(described_class.authentication_path).to start_with(expected_path) | ||
end | ||
|
||
it "supports state parameter" do | ||
path = described_class.authentication_path(state: "state") | ||
expect(path).to include("state=state") | ||
end | ||
|
||
it "provides default state parameter" do | ||
allow(SecureRandom).to receive(:hex).and_return("secure-state") | ||
path = described_class.authentication_path | ||
expect(path).to include("state=secure-state") | ||
end | ||
|
||
it "overrides the callback_url parameter" do | ||
path = described_class.sign_in_path(callback_url: "https://example.com/callback") | ||
expect(path).not_to include("callback_url") | ||
end | ||
end | ||
|
||
describe ".sign_in_path" do | ||
let(:expected_path) do | ||
"/users/auth/osso" | ||
end | ||
|
||
it "returns the correct sign in path" do | ||
expect(described_class.sign_in_path).to start_with(expected_path) | ||
end | ||
|
||
it "supports state parameter" do | ||
path = described_class.sign_in_path(state: "state") | ||
expect(path).to include("state=state") | ||
end | ||
|
||
it "overrides the callback_url parameter" do | ||
path = described_class.sign_in_path(callback_url: "https://example.com/callback") | ||
expect(path).not_to include("callback_url") | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this was throwing a no method error with raw_info being nil