Add support for prompt parameter
This commit is contained in:
parent
8be3be3e10
commit
25f51c606a
4 changed files with 139 additions and 6 deletions
|
|
@ -9,7 +9,13 @@ module Api
|
|||
before_action :authenticate_user!
|
||||
|
||||
def new
|
||||
request_authorization_consent_form
|
||||
auth = Api::OpenidConnect::Authorization.find_by_client_id_and_user(params[:client_id], current_user)
|
||||
if params[:prompt]
|
||||
prompt = params[:prompt].split(" ")
|
||||
handle_prompt(prompt, auth)
|
||||
else
|
||||
handle_authorization_form(auth)
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
|
|
@ -29,12 +35,50 @@ module Api
|
|||
|
||||
private
|
||||
|
||||
def request_authorization_consent_form # TODO: Add support for prompt params
|
||||
if Api::OpenidConnect::Authorization.find_by_client_id_and_user(params[:client_id], current_user)
|
||||
def handle_prompt(prompt, auth)
|
||||
if prompt.include? "select_account"
|
||||
handle_prompt_params_error("account_selection_required",
|
||||
"There is no support for choosing among multiple accounts")
|
||||
elsif prompt.include? "none"
|
||||
handle_prompt_none(prompt, auth)
|
||||
elsif prompt.include?("login") && logged_in_more_than_5_minutes_ago?
|
||||
handle_prompt_params_error("login_required",
|
||||
"There is no support for re-authenticating already authenticated users")
|
||||
elsif prompt.include? "consent"
|
||||
request_authorization_consent_form
|
||||
else
|
||||
handle_authorization_form(auth)
|
||||
end
|
||||
end
|
||||
|
||||
def handle_authorization_form(auth)
|
||||
if auth
|
||||
process_authorization_consent("true")
|
||||
else
|
||||
endpoint = Api::OpenidConnect::AuthorizationPoint::EndpointStartPoint.new(current_user)
|
||||
handle_start_point_response(endpoint)
|
||||
request_authorization_consent_form
|
||||
end
|
||||
end
|
||||
|
||||
def request_authorization_consent_form
|
||||
endpoint = Api::OpenidConnect::AuthorizationPoint::EndpointStartPoint.new(current_user)
|
||||
handle_start_point_response(endpoint)
|
||||
end
|
||||
|
||||
def logged_in_more_than_5_minutes_ago?
|
||||
(current_user.current_sign_in_at.to_i - Time.zone.now.to_i) > 300
|
||||
end
|
||||
|
||||
def handle_prompt_none(prompt, auth)
|
||||
if prompt == ["none"]
|
||||
if auth
|
||||
process_authorization_consent("true")
|
||||
else
|
||||
handle_prompt_params_error("interaction_required",
|
||||
"The Authentication Request cannot be completed without end-user interaction")
|
||||
end
|
||||
else
|
||||
handle_prompt_params_error("invalid_request",
|
||||
"The 'none' value cannot be used with any other prompt value")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -115,6 +159,26 @@ module Api
|
|||
session[:response_type]
|
||||
end
|
||||
end
|
||||
|
||||
def handle_prompt_params_error(error, error_description)
|
||||
if params[:client_id] && params[:redirect_uri]
|
||||
app = Api::OpenidConnect::OAuthApplication.find_by(client_id: params[:client_id])
|
||||
if app && app.redirect_uris.include?(params[:redirect_uri])
|
||||
redirect_prompt_error_display(error, error_description)
|
||||
else
|
||||
render json: {error: "bad_request",
|
||||
description: "No client with client_id " + params[:client_id] + " found"}
|
||||
end
|
||||
else
|
||||
render json: {error: "bad_request", description: "Missing client id or redirect URI"}
|
||||
end
|
||||
end
|
||||
|
||||
def redirect_prompt_error_display(error, error_description)
|
||||
redirect_params_hash = {error: error, error_description: error_description, state: params[:state]}
|
||||
redirect_fragment = redirect_params_hash.compact.map {|key, value| key.to_s + "=" + value }.join("&")
|
||||
redirect_to params[:redirect_uri] + "#" + redirect_fragment
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class UserApplicationsPresenter
|
|||
def find_scopes(application)
|
||||
scopes = Api::OpenidConnect::Authorization.find_by_client_id_and_user(
|
||||
application.client_id, @current_user).scopes
|
||||
scopes.each_with_object([]){|scope, array| array << scope.name }
|
||||
scopes.each_with_object([]) {|scope, array| array << scope.name }
|
||||
end
|
||||
|
||||
def find_id(application)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ o_auth_query_params = %i(
|
|||
scope=openid%20read
|
||||
nonce=hello
|
||||
state=hi
|
||||
prompt=login
|
||||
).join("&")
|
||||
|
||||
Given /^I send a post request from that client to the implicit flow authorization endpoint$/ do
|
||||
|
|
|
|||
|
|
@ -84,6 +84,51 @@ describe Api::OpenidConnect::AuthorizationsController, type: :controller do
|
|||
expect(response.location).to match("error=invalid_request")
|
||||
end
|
||||
end
|
||||
|
||||
context "when prompt is none" do
|
||||
it "should return an interaction required error" do
|
||||
post :new, client_id: client.client_id, redirect_uri: "http://localhost:3000/",
|
||||
response_type: "id_token", scope: "openid", state: 1234, display: "page", prompt: "none"
|
||||
expect(response.location).to match("error=interaction_required")
|
||||
expect(response.location).to match("state=1234")
|
||||
end
|
||||
end
|
||||
|
||||
context "when prompt is none and consent" do
|
||||
it "should return an interaction required error" do
|
||||
post :new, client_id: client.client_id, redirect_uri: "http://localhost:3000/",
|
||||
response_type: "id_token", scope: "openid", state: 1234, display: "page", prompt: "none consent"
|
||||
expect(response.location).to match("error=invalid_request")
|
||||
expect(response.location).to match("state=1234")
|
||||
end
|
||||
end
|
||||
|
||||
context "when prompt is select_account" do
|
||||
it "should return an account_selection_required error" do
|
||||
post :new, client_id: client.client_id, redirect_uri: "http://localhost:3000/",
|
||||
response_type: "id_token", scope: "openid", state: 1234, display: "page", prompt: "select_account"
|
||||
expect(response.location).to match("error=account_selection_required")
|
||||
expect(response.location).to match("state=1234")
|
||||
end
|
||||
end
|
||||
|
||||
context "when prompt is none and client ID is invalid" do
|
||||
it "should return an account_selection_required error" do
|
||||
post :new, client_id: "random", redirect_uri: "http://localhost:3000/",
|
||||
response_type: "id_token", scope: "openid", state: 1234, display: "page", prompt: "none"
|
||||
json_body = JSON.parse(response.body)
|
||||
expect(json_body["error"]).to match("bad_request")
|
||||
end
|
||||
end
|
||||
|
||||
context "when prompt is none and redirect URI does not match pre-registered URIs" do
|
||||
it "should return an account_selection_required error" do
|
||||
post :new, client_id: client.client_id, redirect_uri: "http://randomuri:3000/",
|
||||
response_type: "id_token", scope: "openid", state: 1234, display: "page", prompt: "none"
|
||||
json_body = JSON.parse(response.body)
|
||||
expect(json_body["error"]).to match("bad_request")
|
||||
end
|
||||
end
|
||||
end
|
||||
context "when already authorized" do
|
||||
let!(:auth) {
|
||||
|
|
@ -110,6 +155,29 @@ describe Api::OpenidConnect::AuthorizationsController, type: :controller do
|
|||
expect(response.location).to have_content("state=4130930983")
|
||||
end
|
||||
end
|
||||
|
||||
context "when prompt is none" do
|
||||
it "should return the id token in a fragment" do
|
||||
post :new, client_id: client.client_id, redirect_uri: "http://localhost:3000/",
|
||||
response_type: "id_token", scope: "openid", nonce: 413_093_098_3, state: 413_093_098_3,
|
||||
display: "page", prompt: "none"
|
||||
expect(response.location).to have_content("id_token=")
|
||||
encoded_id_token = response.location[/(?<=id_token=)[^&]+/]
|
||||
decoded_token = OpenIDConnect::ResponseObject::IdToken.decode encoded_id_token,
|
||||
Api::OpenidConnect::IdTokenConfig.public_key
|
||||
expect(decoded_token.nonce).to eq("4130930983")
|
||||
expect(decoded_token.exp).to be > Time.zone.now.utc.to_i
|
||||
end
|
||||
end
|
||||
|
||||
context "when prompt contains consent" do
|
||||
it "should return a consent form page" do
|
||||
get :new, client_id: client.client_id, redirect_uri: "http://localhost:3000/",
|
||||
response_type: "id_token", scope: "openid", nonce: 413_093_098_3, state: 413_093_098_3,
|
||||
display: "page", prompt: "consent"
|
||||
expect(response.body).to match("Diaspora Test Client")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue