FIX: Passkey login when Discourse used as SSO provider (#28672)
Co-authored-by: Osama Sayegh <asooomaasoooma90@gmail.com>
This commit is contained in:
parent
393c2f61ea
commit
8c19104866
|
@ -131,7 +131,12 @@ export default class Login extends Component {
|
|||
|
||||
if (authResult && !authResult.error) {
|
||||
const destinationUrl = cookie("destination_url");
|
||||
if (destinationUrl) {
|
||||
const ssoDestinationUrl = cookie("sso_destination_url");
|
||||
|
||||
if (ssoDestinationUrl) {
|
||||
removeCookie("sso_destination_url");
|
||||
window.location.assign(ssoDestinationUrl);
|
||||
} else if (destinationUrl) {
|
||||
removeCookie("destination_url");
|
||||
window.location.assign(destinationUrl);
|
||||
} else {
|
||||
|
|
|
@ -75,6 +75,7 @@ class SessionController < ApplicationController
|
|||
if request.xhr?
|
||||
# for the login modal
|
||||
cookies[:sso_destination_url] = data[:sso_redirect_url]
|
||||
render json: success_json.merge(redirect_url: data[:sso_redirect_url])
|
||||
else
|
||||
redirect_to data[:sso_redirect_url], allow_other_host: true
|
||||
end
|
||||
|
@ -370,7 +371,7 @@ class SessionController < ApplicationController
|
|||
return render(json: @second_factor_failure_payload) if !second_factor_auth_result.ok
|
||||
|
||||
if user.active && user.email_confirmed?
|
||||
login(user, second_factor_auth_result)
|
||||
login(user, second_factor_auth_result: second_factor_auth_result)
|
||||
else
|
||||
not_activated(user)
|
||||
end
|
||||
|
@ -396,7 +397,7 @@ class SessionController < ApplicationController
|
|||
user = User.where(id: security_key.user_id, active: true).first
|
||||
|
||||
if user.email_confirmed?
|
||||
login(user, false)
|
||||
login(user, passkey_login: true)
|
||||
else
|
||||
not_activated(user)
|
||||
end
|
||||
|
@ -798,17 +799,18 @@ class SessionController < ApplicationController
|
|||
{ error: user.suspended_message, reason: "suspended" }
|
||||
end
|
||||
|
||||
def login(user, second_factor_auth_result)
|
||||
def login(user, passkey_login: false, second_factor_auth_result: nil)
|
||||
session.delete(ACTIVATE_USER_KEY)
|
||||
user.update_timezone_if_missing(params[:timezone])
|
||||
log_on_user(user)
|
||||
|
||||
if payload = cookies.delete(:sso_payload)
|
||||
confirmed_2fa_during_login =
|
||||
(
|
||||
second_factor_auth_result&.ok && second_factor_auth_result.used_2fa_method.present? &&
|
||||
second_factor_auth_result.used_2fa_method != UserSecondFactor.methods[:backup_codes]
|
||||
)
|
||||
passkey_login ||
|
||||
(
|
||||
second_factor_auth_result&.ok && second_factor_auth_result.used_2fa_method.present? &&
|
||||
second_factor_auth_result.used_2fa_method != UserSecondFactor.methods[:backup_codes]
|
||||
)
|
||||
sso_provider(payload, confirmed_2fa_during_login)
|
||||
else
|
||||
render_serialized(user, UserSerializer)
|
||||
|
|
|
@ -1802,7 +1802,7 @@ RSpec.describe SessionController do
|
|||
},
|
||||
xhr: true,
|
||||
headers: headers
|
||||
expect(response.status).to eq(204)
|
||||
expect(response.status).to eq(200)
|
||||
# the frontend will take care of actually redirecting the user
|
||||
redirect_url = response.cookies["sso_destination_url"]
|
||||
expect(redirect_url).to start_with("http://somewhere.over.rainbow/sso?sso=")
|
||||
|
@ -3252,6 +3252,43 @@ RSpec.describe SessionController do
|
|||
|
||||
expect(session[:current_user_id]).to eq(user.id)
|
||||
end
|
||||
|
||||
context "with a valid discourse connect provider" do
|
||||
before do
|
||||
sso = DiscourseConnectBase.new
|
||||
sso.nonce = "mynonce"
|
||||
sso.sso_secret = "topsecret"
|
||||
sso.return_sso_url = "http://somewhere.over.rainbow/sso"
|
||||
cookies[:sso_payload] = sso.payload
|
||||
|
||||
provider_uid = 12_345
|
||||
UserAssociatedAccount.create!(
|
||||
provider_name: "google_oauth2",
|
||||
provider_uid: provider_uid,
|
||||
user: user,
|
||||
)
|
||||
|
||||
SiteSetting.enable_discourse_connect_provider = true
|
||||
SiteSetting.discourse_connect_secret = sso.sso_secret
|
||||
SiteSetting.discourse_connect_provider_secrets =
|
||||
"somewhere.over.rainbow|#{sso.sso_secret}"
|
||||
end
|
||||
|
||||
it "logs the user in" do
|
||||
simulate_localhost_passkey_challenge
|
||||
user.activate
|
||||
user.create_or_fetch_secure_identifier
|
||||
post "/session/passkey/auth.json",
|
||||
params: {
|
||||
publicKeyCredential:
|
||||
valid_passkey_auth_data.merge(
|
||||
{ userHandle: Base64.strict_encode64(user.secure_identifier) },
|
||||
),
|
||||
}
|
||||
expect(response.status).to eq(302)
|
||||
expect(response.location).to start_with("http://somewhere.over.rainbow/sso")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue