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!
|
before_action :authenticate_user!
|
||||||
|
|
||||||
def new
|
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
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
|
@ -29,12 +35,50 @@ module Api
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def request_authorization_consent_form # TODO: Add support for prompt params
|
def handle_prompt(prompt, auth)
|
||||||
if Api::OpenidConnect::Authorization.find_by_client_id_and_user(params[:client_id], current_user)
|
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")
|
process_authorization_consent("true")
|
||||||
else
|
else
|
||||||
endpoint = Api::OpenidConnect::AuthorizationPoint::EndpointStartPoint.new(current_user)
|
request_authorization_consent_form
|
||||||
handle_start_point_response(endpoint)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -115,6 +159,26 @@ module Api
|
||||||
session[:response_type]
|
session[:response_type]
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ class UserApplicationsPresenter
|
||||||
def find_scopes(application)
|
def find_scopes(application)
|
||||||
scopes = Api::OpenidConnect::Authorization.find_by_client_id_and_user(
|
scopes = Api::OpenidConnect::Authorization.find_by_client_id_and_user(
|
||||||
application.client_id, @current_user).scopes
|
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
|
end
|
||||||
|
|
||||||
def find_id(application)
|
def find_id(application)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ o_auth_query_params = %i(
|
||||||
scope=openid%20read
|
scope=openid%20read
|
||||||
nonce=hello
|
nonce=hello
|
||||||
state=hi
|
state=hi
|
||||||
|
prompt=login
|
||||||
).join("&")
|
).join("&")
|
||||||
|
|
||||||
Given /^I send a post request from that client to the implicit flow authorization endpoint$/ do
|
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")
|
expect(response.location).to match("error=invalid_request")
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
context "when already authorized" do
|
context "when already authorized" do
|
||||||
let!(:auth) {
|
let!(:auth) {
|
||||||
|
|
@ -110,6 +155,29 @@ describe Api::OpenidConnect::AuthorizationsController, type: :controller do
|
||||||
expect(response.location).to have_content("state=4130930983")
|
expect(response.location).to have_content("state=4130930983")
|
||||||
end
|
end
|
||||||
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue