Fix travis errors and refactor
This commit is contained in:
parent
c6eb722517
commit
73cc55940d
33 changed files with 237 additions and 420 deletions
|
|
@ -1,10 +1,10 @@
|
||||||
class Api::V0::UsersController < Api::V0::BaseController
|
class Api::V0::UsersController < Api::V0::BaseController
|
||||||
|
|
||||||
def show
|
def show
|
||||||
render json: user
|
render json: user
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def user
|
def user
|
||||||
current_token.user
|
current_token.user
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
This code is based on https://github.com/nov/openid_connect_sample
|
|
||||||
|
|
||||||
Copyright (c) 2011 nov matake
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
class OpenidConnect::AuthorizationsController < ApplicationController
|
class OpenidConnect::AuthorizationsController < ApplicationController
|
||||||
rescue_from Rack::OAuth2::Server::Authorize::BadRequest do |e|
|
rescue_from Rack::OAuth2::Server::Authorize::BadRequest do |e|
|
||||||
logger.info e.backtrace[0,10].join("\n")
|
logger.info e.backtrace[0,10].join("\n")
|
||||||
render json: {error: e.message || :error, status: e.status}
|
render json: { error: e.message || :error, status: e.status }
|
||||||
end
|
end
|
||||||
|
|
||||||
before_action :authenticate_user!
|
before_action :authenticate_user!
|
||||||
|
|
@ -14,50 +14,49 @@ class OpenidConnect::AuthorizationsController < ApplicationController
|
||||||
process_authorization_consent(params[:approve])
|
process_authorization_consent(params[:approve])
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def request_authorization_consent_form
|
def request_authorization_consent_form
|
||||||
endpoint = OpenidConnect::Authorization::EndpointStartPoint.new(current_user)
|
endpoint = OpenidConnect::Authorization::EndpointStartPoint.new(current_user)
|
||||||
handleStartPointResponse(endpoint)
|
handle_startpoint_response(endpoint)
|
||||||
end
|
end
|
||||||
|
|
||||||
def handleStartPointResponse(endpoint)
|
def handle_startpoint_response(endpoint)
|
||||||
status, header, response = *endpoint.call(request.env)
|
_status, header, response = *endpoint.call(request.env)
|
||||||
if response.redirect?
|
if response.redirect?
|
||||||
redirect_to header['Location']
|
redirect_to header["Location"]
|
||||||
else
|
else
|
||||||
@client, @response_type, @redirect_uri, @scopes, @request_object = *[
|
@client, @response_type, @redirect_uri, @scopes, @request_object = *[
|
||||||
endpoint.client, endpoint.response_type, endpoint.redirect_uri, endpoint.scopes, endpoint.request_object
|
endpoint.client, endpoint.response_type, endpoint.redirect_uri, endpoint.scopes, endpoint.request_object
|
||||||
]
|
]
|
||||||
saveRequestParameters
|
save_request_parameters
|
||||||
render :new
|
render :new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def process_authorization_consent(approvedString)
|
def process_authorization_consent(approvedString)
|
||||||
endpoint = OpenidConnect::Authorization::EndpointConfirmationPoint.new(current_user, to_boolean(approvedString))
|
endpoint = OpenidConnect::Authorization::EndpointConfirmationPoint.new(current_user, to_boolean(approvedString))
|
||||||
restoreRequestParameters(endpoint)
|
restore_request_parameters(endpoint)
|
||||||
handleConfirmationPointResponse(endpoint)
|
handle_confirmation_endpoint_response(endpoint)
|
||||||
end
|
end
|
||||||
|
|
||||||
def handleConfirmationPointResponse(endpoint)
|
def handle_confirmation_endpoint_response(endpoint)
|
||||||
status, header, response = *endpoint.call(request.env)
|
_status, header, _response = *endpoint.call(request.env)
|
||||||
redirect_to header['Location']
|
redirect_to header["Location"]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def save_request_parameters
|
||||||
def saveRequestParameters
|
|
||||||
session[:client_id], session[:response_type], session[:redirect_uri], session[:scopes], session[:request_object] =
|
session[:client_id], session[:response_type], session[:redirect_uri], session[:scopes], session[:request_object] =
|
||||||
@client.client_id, @response_type, @redirect_uri, @scopes.collect { |scope| scope.name }, @request_object
|
@client.client_id, @response_type, @redirect_uri, @scopes.map(&:name), @request_object
|
||||||
end
|
end
|
||||||
|
|
||||||
def restoreRequestParameters(endpoint)
|
def restore_request_parameters(endpoint)
|
||||||
req = Rack::Request.new(request.env)
|
req = Rack::Request.new(request.env)
|
||||||
req.update_param("client_id", session[:client_id])
|
req.update_param("client_id", session[:client_id])
|
||||||
req.update_param("redirect_uri", session[:redirect_uri])
|
req.update_param("redirect_uri", session[:redirect_uri])
|
||||||
req.update_param("response_type", session[:response_type])
|
req.update_param("response_type", session[:response_type])
|
||||||
endpoint.scopes, endpoint.request_object =
|
endpoint.scopes, endpoint.request_object =
|
||||||
session[:scopes].collect {|scope| Scope.find_by_name(scope)}, session[:request_object]
|
session[:scopes].map {|scope| Scope.find_by_name(scope) }, session[:request_object]
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_boolean(str)
|
def to_boolean(str)
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
class OpenidConnect::ClientsController < ApplicationController
|
class OpenidConnect::ClientsController < ApplicationController
|
||||||
|
|
||||||
rescue_from OpenIDConnect::HttpError do |e|
|
rescue_from OpenIDConnect::HttpError do |e|
|
||||||
rewriteHTTPErrorPageAsJSON(e)
|
http_error_page_as_json(e)
|
||||||
end
|
end
|
||||||
|
|
||||||
rescue_from OpenIDConnect::ValidationFailed do |e|
|
rescue_from OpenIDConnect::ValidationFailed do |e|
|
||||||
rewriteValidationFailErrorPageAsJSON(e)
|
validation_fail_as_json(e)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
|
@ -13,16 +13,19 @@ class OpenidConnect::ClientsController < ApplicationController
|
||||||
render json: client
|
render json: client
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def rewriteHTTPErrorPageAsJSON(e)
|
def http_error_page_as_json(e)
|
||||||
render json: {
|
render json:
|
||||||
|
{
|
||||||
error: :invalid_request,
|
error: :invalid_request,
|
||||||
error_description: e.message
|
error_description: e.message
|
||||||
}, status: 400
|
}, status: 400
|
||||||
end
|
end
|
||||||
def rewriteValidationFailErrorPageAsJSON(e)
|
|
||||||
render json: {
|
def validation_fail_as_json(e)
|
||||||
|
render json:
|
||||||
|
{
|
||||||
error: :invalid_client_metadata,
|
error: :invalid_client_metadata,
|
||||||
error_description: e.message
|
error_description: e.message
|
||||||
}, status: 400
|
}, status: 400
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
class DiscoveryController < ApplicationController
|
class DiscoveryController < ApplicationController
|
||||||
def show
|
def show
|
||||||
case params[:id]
|
case params[:id]
|
||||||
when 'webfinger'
|
when "webfinger"
|
||||||
webfinger_discovery
|
webfinger_discovery
|
||||||
when 'openid-configuration'
|
when "openid-configuration"
|
||||||
openid_configuration
|
openid_configuration
|
||||||
else
|
else
|
||||||
raise HttpError::NotFound
|
raise HttpError::NotFound
|
||||||
|
|
@ -34,11 +34,11 @@ class DiscoveryController < ApplicationController
|
||||||
scopes_supported: "iss",
|
scopes_supported: "iss",
|
||||||
response_types_supported: "Client.available_response_types",
|
response_types_supported: "Client.available_response_types",
|
||||||
grant_types_supported: "Client.available_grant_types",
|
grant_types_supported: "Client.available_grant_types",
|
||||||
request_object_signing_alg_values_supported: [:HS256, :HS384, :HS512],
|
request_object_signing_alg_values_supported: %i(HS256 HS384 HS512),
|
||||||
subject_types_supported: ['public', 'pairwise'],
|
subject_types_supported: %w(public pairwise),
|
||||||
id_token_signing_alg_values_supported: [:RS256],
|
id_token_signing_alg_values_supported: %i(RS256),
|
||||||
token_endpoint_auth_methods_supported: ['client_secret_basic', 'client_secret_post'],
|
token_endpoint_auth_methods_supported: %w(client_secret_basic client_secret_post),
|
||||||
claims_supported: ['sub', 'iss', 'name', 'email']
|
claims_supported: %w(sub iss name email)
|
||||||
)
|
)
|
||||||
render json: config
|
render json: config
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,7 @@
|
||||||
# the COPYRIGHT file.
|
# the COPYRIGHT file.
|
||||||
|
|
||||||
class UsersController < ApplicationController
|
class UsersController < ApplicationController
|
||||||
|
before_action :authenticate_user!, except: %i(new create public user_photo)
|
||||||
before_action :authenticate_user!, except: [:new, :create, :public, :user_photo]
|
|
||||||
respond_to :html
|
respond_to :html
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
class Authorization < ActiveRecord::Base
|
class Authorization < ActiveRecord::Base
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :o_auth_application
|
belongs_to :o_auth_application
|
||||||
has_and_belongs_to_many :scopes
|
has_many :scopes, through: :authorization_scopes
|
||||||
|
|
||||||
# TODO: Incomplete class
|
# TODO: Incomplete class
|
||||||
end
|
end
|
||||||
|
|
|
||||||
7
app/models/authorization_scope.rb
Normal file
7
app/models/authorization_scope.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
class AuthorizationScope < ActiveRecord::Base
|
||||||
|
belongs_to authorization
|
||||||
|
belongs_to scope
|
||||||
|
|
||||||
|
validates authorization, presence: true
|
||||||
|
validates scope, presence: true
|
||||||
|
end
|
||||||
|
|
@ -19,25 +19,13 @@ class OAuthApplication < ActiveRecord::Base
|
||||||
["id_token"]
|
["id_token"]
|
||||||
end
|
end
|
||||||
|
|
||||||
def register!(registrarHash)
|
def register!(registrar)
|
||||||
registrarHash.validate!
|
registrar.validate!
|
||||||
buildClientApplication(registrarHash)
|
build_client_application(registrar)
|
||||||
end
|
end
|
||||||
|
|
||||||
def buildClientApplication(registrarHash)
|
def build_client_application(registrar)
|
||||||
client = OAuthApplication.create!
|
create! redirect_uris: registrar.redirect_uris
|
||||||
client.attributes = filterNilValues(registrarHash)
|
|
||||||
client.save!
|
|
||||||
client
|
|
||||||
end
|
|
||||||
|
|
||||||
def filterNilValues(registrarHash)
|
|
||||||
{
|
|
||||||
name: registrarHash.client_name,
|
|
||||||
redirect_uris: registrarHash.redirect_uris
|
|
||||||
}.delete_if do |key, value|
|
|
||||||
value.nil?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
class Scope < ActiveRecord::Base
|
class Scope < ActiveRecord::Base
|
||||||
has_and_belongs_to_many :tokens
|
has_many :tokens, through: :scope_tokens
|
||||||
has_and_belongs_to_many :authorizations
|
has_many :authorizations, through: :authorization_scopes
|
||||||
|
|
||||||
validates :name, presence: true, uniqueness: true
|
validates :name, presence: true, uniqueness: true
|
||||||
|
|
||||||
|
|
|
||||||
7
app/models/scopes_tokens.rb
Normal file
7
app/models/scopes_tokens.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
class ScopeToken < ActiveRecord::Base
|
||||||
|
belongs_to :scope
|
||||||
|
belongs_to :token
|
||||||
|
|
||||||
|
validates :scope, presence: true
|
||||||
|
validates :token, presence: true
|
||||||
|
end
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
class Token < ActiveRecord::Base
|
class Token < ActiveRecord::Base
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
has_and_belongs_to_many :scopes
|
has_many :scopes, through: :scope_tokens
|
||||||
|
|
||||||
before_validation :setup, on: :create
|
before_validation :setup, on: :create
|
||||||
|
|
||||||
|
|
@ -20,7 +20,7 @@ class Token < ActiveRecord::Base
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def accessible?(_scopes_or_claims_ = nil)
|
def accessible?(_scopes_or_claims_=nil)
|
||||||
true # TODO: For now don't support scopes
|
true # TODO: For now don't support scopes
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ module Diaspora
|
||||||
}
|
}
|
||||||
config.action_mailer.asset_host = AppConfig.pod_uri.to_s
|
config.action_mailer.asset_host = AppConfig.pod_uri.to_s
|
||||||
|
|
||||||
config.middleware.use Rack::OAuth2::Server::Resource::Bearer, 'OpenID Connect' do |req|
|
config.middleware.use Rack::OAuth2::Server::Resource::Bearer, "OpenID Connect" do |req|
|
||||||
Token.valid(Time.now.utc).find_by(token: req.access_token) || req.invalid_token!
|
Token.valid(Time.now.utc).find_by(token: req.access_token) || req.invalid_token!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -233,17 +233,17 @@ Diaspora::Application.routes.draw do
|
||||||
# Startpage
|
# Startpage
|
||||||
root :to => 'home#show'
|
root :to => 'home#show'
|
||||||
|
|
||||||
#OpenID Connect & OAuth
|
# OpenID Connect & OAuth
|
||||||
namespace :openid_connect do
|
namespace :openid_connect do
|
||||||
resources :clients, only: :create
|
resources :clients, only: :create
|
||||||
post 'access_tokens', to: proc { |env| OpenidConnect::TokenEndpoint.new.call(env) }
|
post "access_tokens", to: proc {|env| OpenidConnect::TokenEndpoint.new.call(env) }
|
||||||
|
|
||||||
# Authorization Servers MUST support the use of the HTTP GET and POST methods at the Authorization Endpoint (see http://openid.net/specs/openid-connect-core-1_0.html#AuthResponseValidation).
|
# Authorization Servers MUST support the use of the HTTP GET and POST methods at the Authorization Endpoint (see http://openid.net/specs/openid-connect-core-1_0.html#AuthResponseValidation).
|
||||||
resources :authorizations, only: [:new, :create]
|
resources :authorizations, only: %i(new create)
|
||||||
post 'authorizations/new', to: 'authorizations#new'
|
post "authorizations/new", to: "authorizations#new"
|
||||||
end
|
end
|
||||||
|
|
||||||
api_version(module: "Api::V0", path: {value: "api/v0"}, default: true) do
|
api_version(module: "Api::V0", path: {value: "api/v0"}, default: true) do
|
||||||
match 'user', to: 'users#show', via: [:get, :post]
|
match "user", to: "users#show", via: [:get, :post]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
class CreateOAuthApplications < ActiveRecord::Migration
|
class CreateOAuthApplications < ActiveRecord::Migration
|
||||||
def self.up
|
def change
|
||||||
create_table :o_auth_applications do |t|
|
create_table :o_auth_applications do |t|
|
||||||
t.belongs_to :user, index: true
|
t.belongs_to :user, index: true
|
||||||
t.string :client_id
|
t.string :client_id
|
||||||
|
|
|
||||||
|
|
@ -1,64 +1,46 @@
|
||||||
When /^I register a new client$/ do
|
When /^I register a new client$/ do
|
||||||
clientRegistrationURL = "/openid_connect/clients"
|
client_registration_url = "/openid_connect/clients"
|
||||||
post clientRegistrationURL,
|
post client_registration_url, redirect_uris: ["http://localhost:3000"] # Not actually used
|
||||||
{
|
|
||||||
redirect_uris: ["http://localhost:3000"] # Not actually used
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
Given /^I send a post request from that client to the token endpoint using "([^\"]*)"'s credentials$/ do |username|
|
Given /^I send a post request from that client to the token endpoint using "([^\"]*)"'s credentials$/ do |username|
|
||||||
clientJSON = JSON.parse(last_response.body)
|
client_json = JSON.parse(last_response.body)
|
||||||
user = User.find_by(username: username)
|
user = User.find_by(username: username)
|
||||||
tokenEndpointURL = "/openid_connect/access_tokens"
|
token_endpoint_url = "/openid_connect/access_tokens"
|
||||||
post tokenEndpointURL,
|
post token_endpoint_url, grant_type: "password", username: user.username,
|
||||||
{
|
|
||||||
grant_type: "password",
|
|
||||||
username: user.username,
|
|
||||||
password: "password", # Password has been hard coded as all test accounts seem to have a password of "password"
|
password: "password", # Password has been hard coded as all test accounts seem to have a password of "password"
|
||||||
client_id: clientJSON["o_auth_application"]["client_id"],
|
client_id: client_json["o_auth_application"]["client_id"],
|
||||||
client_secret: clientJSON["o_auth_application"]["client_secret"]
|
client_secret: client_json["o_auth_application"]["client_secret"]
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
Given /^I send a post request from that client to the token endpoint using invalid credentials$/ do
|
Given /^I send a post request from that client to the token endpoint using invalid credentials$/ do
|
||||||
clientJSON = JSON.parse(last_response.body)
|
client_json = JSON.parse(last_response.body)
|
||||||
tokenEndpointURL = "/openid_connect/access_tokens"
|
token_endpoint_url = "/openid_connect/access_tokens"
|
||||||
post tokenEndpointURL,
|
post token_endpoint_url, grant_type: "password", username: "bob", password: "wrongpassword",
|
||||||
{
|
client_id: client_json["o_auth_application"]["client_id"],
|
||||||
grant_type: "password",
|
client_secret: client_json["o_auth_application"]["client_secret"]
|
||||||
username: User.find_by(username: "bob"),
|
|
||||||
password: "wrongpassword",
|
|
||||||
client_id: clientJSON["o_auth_application"]["client_id"],
|
|
||||||
client_secret: clientJSON["o_auth_application"]["client_secret"]
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
When /^I use received valid bearer tokens to access user info$/ do
|
When /^I use received valid bearer tokens to access user info$/ do
|
||||||
accessTokenJson = JSON.parse(last_response.body)
|
access_token_json = JSON.parse(last_response.body)
|
||||||
userInfoEndPointURL = "/api/v0/user/"
|
user_info_endpoint_url = "/api/v0/user/"
|
||||||
get userInfoEndPointURL,
|
get user_info_endpoint_url, access_token: access_token_json["access_token"]
|
||||||
{
|
|
||||||
access_token: accessTokenJson["access_token"]
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
When /^I use invalid bearer tokens to access user info$/ do
|
When /^I use invalid bearer tokens to access user info$/ do
|
||||||
userInfoEndPointURL = "/api/v0/user/"
|
user_info_endpoint_url = "/api/v0/user/"
|
||||||
get userInfoEndPointURL,
|
get user_info_endpoint_url, access_token: SecureRandom.hex(32)
|
||||||
{
|
|
||||||
access_token: SecureRandom.hex(32)
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
Then /^I should receive "([^\"]*)"'s id, username, and email$/ do |username|
|
Then /^I should receive "([^\"]*)"'s id, username, and email$/ do |username|
|
||||||
userInfoJson = JSON.parse(last_response.body)
|
user_info_json = JSON.parse(last_response.body)
|
||||||
user = User.find_by_username(username)
|
user = User.find_by_username(username)
|
||||||
expect(userInfoJson["username"]).to have_content(user.username)
|
expect(user_info_json["username"]).to have_content(user.username)
|
||||||
expect(userInfoJson["language"]).to have_content(user.language)
|
expect(user_info_json["language"]).to have_content(user.language)
|
||||||
expect(userInfoJson["email"]).to have_content(user.email)
|
expect(user_info_json["email"]).to have_content(user.email)
|
||||||
end
|
end
|
||||||
|
|
||||||
Then /^I should receive an "([^\"]*)" error$/ do |error_message|
|
Then /^I should receive an "([^\"]*)" error$/ do |error_message|
|
||||||
userInfoJson = JSON.parse(last_response.body)
|
user_info_json = JSON.parse(last_response.body)
|
||||||
expect(userInfoJson["error"]).to have_content(error_message)
|
expect(user_info_json["error"]).to have_content(error_message)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,8 @@ class AccountDeleter
|
||||||
|
|
||||||
#user deletions
|
#user deletions
|
||||||
def normal_ar_user_associates_to_delete
|
def normal_ar_user_associates_to_delete
|
||||||
[:tag_followings, :invitations_to_me, :services, :aspects, :user_preferences, :notifications, :blocks]
|
%i(tag_followings invitations_to_me services aspects user_preferences
|
||||||
|
notifications blocks authorizations o_auth_applications tokens)
|
||||||
end
|
end
|
||||||
|
|
||||||
def special_ar_user_associations
|
def special_ar_user_associations
|
||||||
|
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
This code is based on https://github.com/nov/openid_connect_sample
|
|
||||||
|
|
||||||
Copyright (c) 2011 nov matake
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
@ -1,35 +1,38 @@
|
||||||
module OpenidConnect
|
module OpenidConnect
|
||||||
module Authorization
|
module Authorization
|
||||||
class Endpoint
|
class Endpoint
|
||||||
attr_accessor :app, :user, :client, :redirect_uri, :response_type, :scopes, :_request_, :request_uri, :request_object
|
attr_accessor :app, :user, :client, :redirect_uri, :response_type,
|
||||||
|
:scopes, :_request_, :request_uri, :request_object
|
||||||
delegate :call, to: :app
|
delegate :call, to: :app
|
||||||
|
|
||||||
def initialize(current_user)
|
def initialize(current_user)
|
||||||
@user = current_user
|
@user = current_user
|
||||||
@app = Rack::OAuth2::Server::Authorize.new do |req, res|
|
@app = Rack::OAuth2::Server::Authorize.new do |req, res|
|
||||||
buildAttributes(req, res)
|
build_attributes(req, res)
|
||||||
if OAuthApplication.available_response_types.include? Array(req.response_type).collect(&:to_s).join(' ')
|
if OAuthApplication.available_response_types.include? Array(req.response_type).map(&:to_s).join(" ")
|
||||||
handleResponseType(req, res)
|
handle_response_type(req, res)
|
||||||
else
|
else
|
||||||
req.unsupported_response_type!
|
req.unsupported_response_type!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
def buildAttributes(req, res)
|
|
||||||
buildClient(req)
|
def build_attributes(req, res)
|
||||||
buildRedirectURI(req, res)
|
build_client(req)
|
||||||
|
build_redirect_uri(req, res)
|
||||||
end
|
end
|
||||||
|
|
||||||
def handleResponseType(req, res)
|
def handle_response_type(req, res)
|
||||||
# Implemented by subclass
|
# Implemented by subclass
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def buildClient(req)
|
def build_client(req)
|
||||||
@client = OAuthApplication.find_by_client_id(req.client_id) || req.bad_request!
|
@client = OAuthApplication.find_by_client_id(req.client_id) || req.bad_request!
|
||||||
end
|
end
|
||||||
def buildRedirectURI(req, res)
|
|
||||||
|
def build_redirect_uri(req, res)
|
||||||
res.redirect_uri = @redirect_uri = req.verify_redirect_uri!(@client.redirect_uris)
|
res.redirect_uri = @redirect_uri = req.verify_redirect_uri!(@client.redirect_uris)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,21 @@
|
||||||
module OpenidConnect
|
module OpenidConnect
|
||||||
module Authorization
|
module Authorization
|
||||||
class EndpointConfirmationPoint < Endpoint
|
class EndpointConfirmationPoint < Endpoint
|
||||||
def initialize(current_user, approved = false)
|
def initialize(current_user, approved=false)
|
||||||
super(current_user)
|
super(current_user)
|
||||||
@approved = approved
|
@approved = approved
|
||||||
end
|
end
|
||||||
|
|
||||||
def buildAttributes(req, res)
|
def build_attributes(req, res)
|
||||||
super(req, res)
|
super(req, res)
|
||||||
# TODO: buildResponseType(req)
|
# TODO: buildResponseType(req)
|
||||||
end
|
end
|
||||||
|
|
||||||
def handleResponseType(req, res)
|
def handle_response_type(req, res)
|
||||||
handleApproval(@approved, req, res)
|
handle_approval(@approved, req, res)
|
||||||
end
|
end
|
||||||
|
|
||||||
def handleApproval(approved, req, res)
|
def handle_approval(approved, req, res)
|
||||||
if approved
|
if approved
|
||||||
approved!(req, res)
|
approved!(req, res)
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -4,24 +4,30 @@ module OpenidConnect
|
||||||
def initialize(current_user)
|
def initialize(current_user)
|
||||||
super(current_user)
|
super(current_user)
|
||||||
end
|
end
|
||||||
def handleResponseType(req, res)
|
|
||||||
|
def handle_response_type(req, res)
|
||||||
@response_type = req.response_type
|
@response_type = req.response_type
|
||||||
end
|
end
|
||||||
def buildAttributes(req, res)
|
|
||||||
|
def build_attributes(req, res)
|
||||||
super(req, res)
|
super(req, res)
|
||||||
verifyNonce(req, res)
|
verify_nonce(req, res)
|
||||||
buildScopes(req)
|
build_scopes(req)
|
||||||
# TODO: buildRequestObject(req)
|
# TODO: buildRequestObject(req)
|
||||||
end
|
end
|
||||||
def verifyNonce(req, res)
|
|
||||||
|
def verify_nonce(req, res)
|
||||||
if res.protocol_params_location == :fragment && req.nonce.blank?
|
if res.protocol_params_location == :fragment && req.nonce.blank?
|
||||||
req.invalid_request! "nonce required"
|
req.invalid_request! "nonce required"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
def buildScopes(req)
|
|
||||||
@scopes = req.scope.inject([]) do |_scopes_, scope|
|
def build_scopes(req)
|
||||||
_scopes_ << (Scope.find_by_name(scope) or req.invalid_scope! "Unknown scope: #{scope}")
|
@scopes = req.scope.map {|scope|
|
||||||
|
Scope.where(name: scope).first.tap do |scope|
|
||||||
|
req.invalid_scope! "Unknown scope: #{scope}" unless scope
|
||||||
end
|
end
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
module OpenidConnect
|
module OpenidConnect
|
||||||
module ProtectedResourceEndpoint
|
module ProtectedResourceEndpoint
|
||||||
|
|
||||||
def self.included(klass)
|
def self.included(klass)
|
||||||
klass.send :include, ProtectedResourceEndpoint::Helper
|
klass.send :include, ProtectedResourceEndpoint::Helper
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -5,25 +5,25 @@ module OpenidConnect
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@app = Rack::OAuth2::Server::Token.new do |req, res|
|
@app = Rack::OAuth2::Server::Token.new do |req, res|
|
||||||
o_auth_app = retrieveClient(req)
|
o_auth_app = retrieve_client(req)
|
||||||
if isAppValid(o_auth_app, req)
|
if app_valid?(o_auth_app, req)
|
||||||
handleFlows(req, res)
|
handle_flows(req, res)
|
||||||
else
|
else
|
||||||
req.invalid_client!
|
req.invalid_client!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def handleFlows(req, res)
|
def handle_flows(req, res)
|
||||||
case req.grant_type
|
case req.grant_type
|
||||||
when :password
|
when :password
|
||||||
handlePasswordFlow(req, res)
|
handle_password_flow(req, res)
|
||||||
else
|
else
|
||||||
req.unsupported_grant_type!
|
req.unsupported_grant_type!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def handlePasswordFlow(req, res)
|
def handle_password_flow(req, res)
|
||||||
user = User.find_for_database_authentication(username: req.username)
|
user = User.find_for_database_authentication(username: req.username)
|
||||||
if user
|
if user
|
||||||
if user.valid_password?(req.password)
|
if user.valid_password?(req.password)
|
||||||
|
|
@ -36,11 +36,11 @@ module OpenidConnect
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def retrieveClient(req)
|
def retrieve_client(req)
|
||||||
OAuthApplication.find_by_client_id req.client_id
|
OAuthApplication.find_by_client_id req.client_id
|
||||||
end
|
end
|
||||||
|
|
||||||
def isAppValid(o_auth_app, req)
|
def app_valid?(o_auth_app, req)
|
||||||
o_auth_app.client_secret == req.client_secret
|
o_auth_app.client_secret == req.client_secret
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
require 'spec_helper'
|
require "spec_helper"
|
||||||
|
|
||||||
describe Api::V0::BaseController do
|
describe Api::V0::BaseController do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,16 @@
|
||||||
require 'spec_helper'
|
require "spec_helper"
|
||||||
|
|
||||||
describe OpenidConnect::AuthorizationsController, type: :controller do
|
describe OpenidConnect::AuthorizationsController, type: :controller do
|
||||||
let!(:client) { OAuthApplication.create!(name: "Diaspora Test Client", redirect_uris: ["http://localhost:3000/"]) }
|
let!(:client) { OAuthApplication.create!(name: "Diaspora Test Client", redirect_uris: ["http://localhost:3000/"]) }
|
||||||
let!(:client_with_multiple_redirects) { OAuthApplication.create!(name: "Diaspora Test Client", redirect_uris: ["http://localhost:3000/","http://localhost/"]) }
|
let!(:client_with_multiple_redirects) do
|
||||||
|
OAuthApplication.create!(
|
||||||
|
name: "Diaspora Test Client", redirect_uris: ["http://localhost:3000/", "http://localhost/"])
|
||||||
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
sign_in :user, alice
|
sign_in :user, alice
|
||||||
allow(@controller).to receive(:current_user).and_return(alice)
|
allow(@controller).to receive(:current_user).and_return(alice)
|
||||||
Scope.create!(name:"openid")
|
Scope.create!(name: "openid")
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#new" do
|
describe "#new" do
|
||||||
|
|
@ -15,113 +18,71 @@ describe OpenidConnect::AuthorizationsController, type: :controller do
|
||||||
render_views
|
render_views
|
||||||
context "as GET request" do
|
context "as GET request" do
|
||||||
it "should return a form page" do
|
it "should return a form page" do
|
||||||
get :new,
|
get :new, client_id: client.client_id, redirect_uri: "http://localhost:3000/", response_type: "id_token",
|
||||||
{
|
scope: "openid", nonce: SecureRandom.hex(16), state: SecureRandom.hex(16)
|
||||||
client_id: client.client_id,
|
|
||||||
redirect_uri: "http://localhost:3000/",
|
|
||||||
response_type: "id_token",
|
|
||||||
scope: "openid",
|
|
||||||
nonce: SecureRandom.hex(16),
|
|
||||||
state: SecureRandom.hex(16)
|
|
||||||
}
|
|
||||||
expect(response.body).to match("Diaspora Test Client")
|
expect(response.body).to match("Diaspora Test Client")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "as POST request" do
|
context "as POST request" do
|
||||||
it "should return a form page" do
|
it "should return a form page" do
|
||||||
post :new,
|
post :new, client_id: client.client_id, redirect_uri: "http://localhost:3000/", response_type: "id_token",
|
||||||
{
|
scope: "openid", nonce: SecureRandom.hex(16), state: SecureRandom.hex(16)
|
||||||
client_id: client.client_id,
|
|
||||||
redirect_uri: "http://localhost:3000/",
|
|
||||||
response_type: "id_token",
|
|
||||||
scope: "openid",
|
|
||||||
nonce: SecureRandom.hex(16),
|
|
||||||
state: SecureRandom.hex(16)
|
|
||||||
}
|
|
||||||
expect(response.body).to match("Diaspora Test Client")
|
expect(response.body).to match("Diaspora Test Client")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when client id is missing" do
|
context "when client id is missing" do
|
||||||
it "should return an bad request error" do
|
it "should return an bad request error" do
|
||||||
post :new,
|
post :new, redirect_uri: "http://localhost:3000/", response_type: "id_token",
|
||||||
{
|
scope: "openid", nonce: SecureRandom.hex(16), state: SecureRandom.hex(16)
|
||||||
redirect_uri: "http://localhost:3000/",
|
|
||||||
response_type: "id_token",
|
|
||||||
scope: "openid",
|
|
||||||
nonce: SecureRandom.hex(16),
|
|
||||||
state: SecureRandom.hex(16)
|
|
||||||
}
|
|
||||||
expect(response.body).to match("bad_request")
|
expect(response.body).to match("bad_request")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when redirect uri is missing" do
|
context "when redirect uri is missing" do
|
||||||
context "when only one redirect URL is pre-registered" do
|
context "when only one redirect URL is pre-registered" do
|
||||||
it "should return a form pager" do
|
it "should return a form pager" do
|
||||||
# Note this intentionally behavior diverts from OIDC spec http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
|
# Note this intentionally behavior diverts from OIDC spec http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
|
||||||
|
# When client has only one redirect uri registered, only that redirect uri can be used. Hence,
|
||||||
|
# we should implicitly assume the client wants to use that registered URI.
|
||||||
# See https://github.com/nov/rack-oauth2/blob/master/lib/rack/oauth2/server/authorize.rb#L63
|
# See https://github.com/nov/rack-oauth2/blob/master/lib/rack/oauth2/server/authorize.rb#L63
|
||||||
post :new,
|
post :new, client_id: client.client_id, response_type: "id_token",
|
||||||
{
|
scope: "openid", nonce: SecureRandom.hex(16), state: SecureRandom.hex(16)
|
||||||
client_id: client.client_id,
|
|
||||||
response_type: "id_token",
|
|
||||||
scope: "openid",
|
|
||||||
nonce: SecureRandom.hex(16),
|
|
||||||
state: SecureRandom.hex(16)
|
|
||||||
}
|
|
||||||
expect(response.body).to match("Diaspora Test Client")
|
expect(response.body).to match("Diaspora Test Client")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when multiple redirect URLs are pre-registered" do
|
context "when multiple redirect URLs are pre-registered" do
|
||||||
it "should return an invalid request error" do
|
it "should return an invalid request error" do
|
||||||
post :new,
|
post :new, client_id: client_with_multiple_redirects.client_id, response_type: "id_token",
|
||||||
{
|
scope: "openid", nonce: SecureRandom.hex(16), state: SecureRandom.hex(16)
|
||||||
client_id: client_with_multiple_redirects.client_id,
|
|
||||||
response_type: "id_token",
|
|
||||||
scope: "openid",
|
|
||||||
nonce: SecureRandom.hex(16),
|
|
||||||
state: SecureRandom.hex(16)
|
|
||||||
}
|
|
||||||
expect(response.body).to match("bad_request")
|
expect(response.body).to match("bad_request")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when redirect URI does not match pre-registered URIs" do
|
context "when redirect URI does not match pre-registered URIs" do
|
||||||
it "should return an invalid request error" do
|
it "should return an invalid request error" do
|
||||||
post :new,
|
post :new, client_id: client.client_id, redirect_uri: "http://localhost:2000/",
|
||||||
{
|
response_type: "id_token", scope: "openid", nonce: SecureRandom.hex(16)
|
||||||
client_id: client.client_id,
|
|
||||||
redirect_uri: "http://localhost:2000/",
|
|
||||||
response_type: "id_token",
|
|
||||||
scope: "openid",
|
|
||||||
nonce: SecureRandom.hex(16)
|
|
||||||
}
|
|
||||||
expect(response.body).to match("bad_request")
|
expect(response.body).to match("bad_request")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when an unsupported scope is passed in" do
|
context "when an unsupported scope is passed in" do
|
||||||
it "should return an invalid scope error" do
|
it "should return an invalid scope error" do
|
||||||
post :new,
|
post :new, client_id: client.client_id, redirect_uri: "http://localhost:3000/", response_type: "id_token",
|
||||||
{
|
scope: "random", nonce: SecureRandom.hex(16), state: SecureRandom.hex(16)
|
||||||
client_id: client.client_id,
|
|
||||||
redirect_uri: "http://localhost:3000/",
|
|
||||||
response_type: "id_token",
|
|
||||||
scope: "random",
|
|
||||||
nonce: SecureRandom.hex(16),
|
|
||||||
state: SecureRandom.hex(16)
|
|
||||||
}
|
|
||||||
expect(response.body).to match("error=invalid_scope")
|
expect(response.body).to match("error=invalid_scope")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when nonce is missing" do
|
context "when nonce is missing" do
|
||||||
it "should return an invalid request error" do
|
it "should return an invalid request error" do
|
||||||
post :new,
|
post :new, client_id: client.client_id, redirect_uri: "http://localhost:3000/",
|
||||||
{
|
response_type: "id_token", scope: "openid", state: SecureRandom.hex(16)
|
||||||
client_id: client.client_id,
|
|
||||||
redirect_uri: "http://localhost:3000/",
|
|
||||||
response_type: "id_token",
|
|
||||||
scope: "openid",
|
|
||||||
state: SecureRandom.hex(16)
|
|
||||||
}
|
|
||||||
expect(response.location).to match("error=invalid_request")
|
expect(response.location).to match("error=invalid_request")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -129,44 +90,36 @@ describe OpenidConnect::AuthorizationsController, type: :controller do
|
||||||
|
|
||||||
describe "#create" do
|
describe "#create" do
|
||||||
before do
|
before do
|
||||||
get :new,
|
get :new, client_id: client.client_id, redirect_uri: "http://localhost:3000/", response_type: "id_token",
|
||||||
{
|
scope: "openid", nonce: SecureRandom.hex(16), state: 418_093_098_3
|
||||||
client_id: client.client_id,
|
|
||||||
redirect_uri: "http://localhost:3000/",
|
|
||||||
response_type: "id_token",
|
|
||||||
scope: "openid",
|
|
||||||
nonce: SecureRandom.hex(16),
|
|
||||||
state: 4180930983
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when authorization is approved" do
|
context "when authorization is approved" do
|
||||||
before do
|
before do
|
||||||
post :create,
|
post :create, approve: "true"
|
||||||
{
|
|
||||||
approve: "true"
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should return the id token in a fragment" do
|
it "should return the id token in a fragment" do
|
||||||
expect(response.location).to have_content("id_token=")
|
expect(response.location).to have_content("id_token=")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should return the passed in state" do
|
it "should return the passed in state" do
|
||||||
expect(response.location).to have_content("state=4180930983")
|
expect(response.location).to have_content("state=4180930983")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when authorization is denied" do
|
context "when authorization is denied" do
|
||||||
before do
|
before do
|
||||||
post :create,
|
post :create, approve: "false"
|
||||||
{
|
|
||||||
approve: "false"
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should return an error in the fragment" do
|
it "should return an error in the fragment" do
|
||||||
expect(response.location).to have_content("error=")
|
expect(response.location).to have_content("error=")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should NOT contain a id token in the fragment" do
|
it "should NOT contain a id token in the fragment" do
|
||||||
expect(response.location).to_not have_content("id_token=")
|
expect(response.location).to_not have_content("id_token=")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,19 @@
|
||||||
require 'spec_helper'
|
require "spec_helper"
|
||||||
|
|
||||||
describe OpenidConnect::ClientsController, type: :controller do
|
describe OpenidConnect::ClientsController, type: :controller do
|
||||||
describe "#create" do
|
describe "#create" do
|
||||||
context "when valid parameters are passed" do
|
context "when valid parameters are passed" do
|
||||||
it "should return a client id" do
|
it "should return a client id" do
|
||||||
post :create,
|
post :create, redirect_uris: ["http://localhost"]
|
||||||
{
|
client_json = JSON.parse(response.body)
|
||||||
redirect_uris: ["http://localhost"]
|
expect(client_json["o_auth_application"]["client_id"].length).to eq(32)
|
||||||
}
|
|
||||||
clientJSON = JSON.parse(response.body)
|
|
||||||
expect(clientJSON["o_auth_application"]["client_id"].length).to eq(32)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
context "when redirect uri is missing" do
|
context "when redirect uri is missing" do
|
||||||
it "should return a invalid_client_metadata error" do
|
it "should return a invalid_client_metadata error" do
|
||||||
post :create
|
post :create
|
||||||
clientJSON = JSON.parse(response.body)
|
client_json = JSON.parse(response.body)
|
||||||
expect(clientJSON["error"]).to have_content("invalid_client_metadata")
|
expect(client_json["error"]).to have_content("invalid_client_metadata")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
require 'spec_helper'
|
require "spec_helper"
|
||||||
|
|
||||||
describe OpenidConnect::ProtectedResourceEndpoint, type: :request do
|
describe OpenidConnect::ProtectedResourceEndpoint, type: :request do
|
||||||
describe "getting the user info" do
|
describe "getting the user info" do
|
||||||
|
|
@ -8,19 +8,13 @@ describe OpenidConnect::ProtectedResourceEndpoint, type: :request do
|
||||||
|
|
||||||
context "when access token is valid" do
|
context "when access token is valid" do
|
||||||
it "shows the user's username and email" do
|
it "shows the user's username and email" do
|
||||||
get "/api/v0/user/",
|
get "/api/v0/user/", access_token: token
|
||||||
{
|
json_body = JSON.parse(response.body)
|
||||||
access_token: token
|
expect(json_body["username"]).to eq(bob.username)
|
||||||
}
|
expect(json_body["email"]).to eq(bob.email)
|
||||||
jsonBody = JSON.parse(response.body)
|
|
||||||
expect(jsonBody["username"]).to eq(bob.username)
|
|
||||||
expect(jsonBody["email"]).to eq(bob.email)
|
|
||||||
end
|
end
|
||||||
it "should include private in the cache-control header" do
|
it "should include private in the cache-control header" do
|
||||||
get "/api/v0/user/",
|
get "/api/v0/user/", access_token: token
|
||||||
{
|
|
||||||
access_token: token
|
|
||||||
}
|
|
||||||
expect(response.headers["Cache-Control"]).to include("private")
|
expect(response.headers["Cache-Control"]).to include("private")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -38,24 +32,15 @@ describe OpenidConnect::ProtectedResourceEndpoint, type: :request do
|
||||||
|
|
||||||
context "when an invalid access token is provided" do
|
context "when an invalid access token is provided" do
|
||||||
it "should respond with a 401 Unauthorized response" do
|
it "should respond with a 401 Unauthorized response" do
|
||||||
get "/api/v0/user/",
|
get "/api/v0/user/", access_token: invalid_token
|
||||||
{
|
|
||||||
access_token: invalid_token
|
|
||||||
}
|
|
||||||
expect(response.status).to be(401)
|
expect(response.status).to be(401)
|
||||||
end
|
end
|
||||||
it "should have an auth-scheme value of Bearer" do
|
it "should have an auth-scheme value of Bearer" do
|
||||||
get "/api/v0/user/",
|
get "/api/v0/user/", access_token: invalid_token
|
||||||
{
|
|
||||||
access_token: invalid_token
|
|
||||||
}
|
|
||||||
expect(response.headers["WWW-Authenticate"]).to include("Bearer")
|
expect(response.headers["WWW-Authenticate"]).to include("Bearer")
|
||||||
end
|
end
|
||||||
it "should contain an invalid_token error" do
|
it "should contain an invalid_token error" do
|
||||||
get "/api/v0/user/",
|
get "/api/v0/user/", access_token: invalid_token
|
||||||
{
|
|
||||||
access_token: invalid_token
|
|
||||||
}
|
|
||||||
expect(response.body).to include("invalid_token")
|
expect(response.body).to include("invalid_token")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,68 +1,40 @@
|
||||||
require 'spec_helper'
|
require "spec_helper"
|
||||||
|
|
||||||
describe OpenidConnect::TokenEndpoint, type: :request do
|
describe OpenidConnect::TokenEndpoint, type: :request do
|
||||||
let!(:client) { OAuthApplication.create!(redirect_uris: ["http://localhost"]) }
|
let!(:client) { OAuthApplication.create!(redirect_uris: ["http://localhost"]) }
|
||||||
describe "the password grant type" do
|
describe "the password grant type" do
|
||||||
context "when the username field is missing" do
|
context "when the username field is missing" do
|
||||||
it "should return an invalid request error" do
|
it "should return an invalid request error" do
|
||||||
post "/openid_connect/access_tokens",
|
post "/openid_connect/access_tokens", grant_type: "password", password: "bluepin7",
|
||||||
{
|
client_id: client.client_id, client_secret: client.client_secret
|
||||||
grant_type: "password",
|
|
||||||
password: "bluepin7",
|
|
||||||
client_id: client.client_id,
|
|
||||||
client_secret: client.client_secret
|
|
||||||
}
|
|
||||||
expect(response.body).to include("'username' required")
|
expect(response.body).to include("'username' required")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
context "when the password field is missing" do
|
context "when the password field is missing" do
|
||||||
it "should return an invalid request error" do
|
it "should return an invalid request error" do
|
||||||
post "/openid_connect/access_tokens",
|
post "/openid_connect/access_tokens", grant_type: "password", username: "bob",
|
||||||
{
|
client_id: client.client_id, client_secret: client.client_secret
|
||||||
grant_type: "password",
|
|
||||||
username: "bob",
|
|
||||||
client_id: client.client_id,
|
|
||||||
client_secret: client.client_secret
|
|
||||||
}
|
|
||||||
expect(response.body).to include("'password' required")
|
expect(response.body).to include("'password' required")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
context "when the username does not match an existing user" do
|
context "when the username does not match an existing user" do
|
||||||
it "should return an invalid request error" do
|
it "should return an invalid request error" do
|
||||||
post "/openid_connect/access_tokens",
|
post "/openid_connect/access_tokens", grant_type: "password", username: "randomnoexist",
|
||||||
{
|
password: "bluepin7", client_id: client.client_id, client_secret: client.client_secret
|
||||||
grant_type: "password",
|
|
||||||
username: "randomnoexist",
|
|
||||||
password: "bluepin7",
|
|
||||||
client_id: client.client_id,
|
|
||||||
client_secret: client.client_secret
|
|
||||||
}
|
|
||||||
expect(response.body).to include("invalid_grant")
|
expect(response.body).to include("invalid_grant")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
context "when the password is invalid" do
|
context "when the password is invalid" do
|
||||||
it "should return an invalid request error" do
|
it "should return an invalid request error" do
|
||||||
post "/openid_connect/access_tokens",
|
post "/openid_connect/access_tokens", grant_type: "password", username: "bob",
|
||||||
{
|
password: "wrongpassword", client_id: client.client_id, client_secret: client.client_secret
|
||||||
grant_type: "password",
|
|
||||||
username: "bob",
|
|
||||||
password: "wrongpassword",
|
|
||||||
client_id: client.client_id,
|
|
||||||
client_secret: client.client_secret
|
|
||||||
}
|
|
||||||
expect(response.body).to include("invalid_grant")
|
expect(response.body).to include("invalid_grant")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
context "when the request is valid" do
|
context "when the request is valid" do
|
||||||
it "should return an access token" do
|
it "should return an access token" do
|
||||||
post "/openid_connect/access_tokens",
|
post "/openid_connect/access_tokens", grant_type: "password", username: "bob",
|
||||||
{
|
password: "bluepin7", client_id: client.client_id, client_secret: client.client_secret
|
||||||
grant_type: "password",
|
|
||||||
username: "bob",
|
|
||||||
password: "bluepin7",
|
|
||||||
client_id: client.client_id,
|
|
||||||
client_secret: client.client_secret
|
|
||||||
}
|
|
||||||
json = JSON.parse(response.body)
|
json = JSON.parse(response.body)
|
||||||
expect(json["access_token"].length).to eq(64)
|
expect(json["access_token"].length).to eq(64)
|
||||||
expect(json["token_type"]).to eq("bearer")
|
expect(json["token_type"]).to eq("bearer")
|
||||||
|
|
@ -71,44 +43,25 @@ describe OpenidConnect::TokenEndpoint, type: :request do
|
||||||
end
|
end
|
||||||
context "when there are duplicate fields" do
|
context "when there are duplicate fields" do
|
||||||
it "should return an invalid request error" do
|
it "should return an invalid request error" do
|
||||||
post "/openid_connect/access_tokens",
|
post "/openid_connect/access_tokens", grant_type: "password", username: "bob", password: "bluepin7",
|
||||||
{
|
username: "bob", password: "bluepin6", client_id: client.client_id, client_secret: client.client_secret
|
||||||
grant_type: "password",
|
|
||||||
username: "bob",
|
|
||||||
password: "bluepin7",
|
|
||||||
username: "bob",
|
|
||||||
password: "bluepin6",
|
|
||||||
client_id: client.client_id,
|
|
||||||
client_secret: client.client_secret
|
|
||||||
}
|
|
||||||
expect(response.body).to include("invalid_grant")
|
expect(response.body).to include("invalid_grant")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
context "when the client is unregistered" do
|
context "when the client is unregistered" do
|
||||||
it "should return an error" do
|
it "should return an error" do
|
||||||
post "/openid_connect/access_tokens",
|
post "/openid_connect/access_tokens", grant_type: "password", username: "bob",
|
||||||
{
|
password: "bluepin7", client_id: SecureRandom.hex(16).to_s, client_secret: client.client_secret
|
||||||
grant_type: "password",
|
|
||||||
username: "bob",
|
|
||||||
password: "bluepin7",
|
|
||||||
client_id: SecureRandom.hex(16).to_s,
|
|
||||||
client_secret: client.client_secret
|
|
||||||
}
|
|
||||||
expect(response.body).to include("invalid_client")
|
expect(response.body).to include("invalid_client")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# TODO: Support a way to prevent brute force attacks using rate-limitation? as specified by RFC 6749 4.3.2 Access Token Request
|
# TODO: Support a way to prevent brute force attacks using rate-limitation
|
||||||
|
# as specified by RFC 6749 4.3.2 Access Token Request
|
||||||
end
|
end
|
||||||
describe "an unsupported grant type" do
|
describe "an unsupported grant type" do
|
||||||
it "should return an unsupported grant type error" do
|
it "should return an unsupported grant type error" do
|
||||||
post "/openid_connect/access_tokens",
|
post "/openid_connect/access_tokens", grant_type: "noexistgrant", username: "bob",
|
||||||
{
|
password: "bluepin7", client_id: client.client_id, client_secret: client.client_secret
|
||||||
grant_type: "noexistgrant",
|
|
||||||
username: "bob",
|
|
||||||
password: "bluepin7",
|
|
||||||
client_id: client.client_id,
|
|
||||||
client_secret: client.client_secret
|
|
||||||
}
|
|
||||||
expect(response.body).to include "unsupported_grant_type"
|
expect(response.body).to include "unsupported_grant_type"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
require 'rails_helper'
|
|
||||||
|
|
||||||
RSpec.describe OAuthApplication, type: :model do
|
|
||||||
pending "add some examples to (or delete) #{__FILE__}"
|
|
||||||
end
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
require 'rails_helper'
|
|
||||||
|
|
||||||
RSpec.describe Token, type: :model do
|
|
||||||
pending "add some examples to (or delete) #{__FILE__}"
|
|
||||||
end
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
require 'spec_helper'
|
require "spec_helper"
|
||||||
|
|
||||||
describe Api::V0::BasePresenter do
|
describe Api::V0::BasePresenter do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
require 'spec_helper'
|
require "spec_helper"
|
||||||
|
|
||||||
describe Api::V0::BaseController do
|
describe Api::V0::BaseController do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -59,14 +59,6 @@ def photo_fixture_name
|
||||||
@photo_fixture_name = File.join(File.dirname(__FILE__), "fixtures", "button.png")
|
@photo_fixture_name = File.join(File.dirname(__FILE__), "fixtures", "button.png")
|
||||||
end
|
end
|
||||||
|
|
||||||
def retrieveAccessToken(user)
|
|
||||||
o_auth_app = OAuthApplication.create!(client_id: 4, client_secret: "azerty")
|
|
||||||
user = User.find_for_database_authentication(username: user.username)
|
|
||||||
if o_auth_app && user && user.valid_password?("bluepin7") # Hard coded password for bob
|
|
||||||
o_auth_app.tokens.create!.bearer_token.to_s
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Force fixture rebuild
|
# Force fixture rebuild
|
||||||
FileUtils.rm_f(Rails.root.join("tmp", "fixture_builder.yml"))
|
FileUtils.rm_f(Rails.root.join("tmp", "fixture_builder.yml"))
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue