Skip to content
Extraits de code Groupes Projets
Valider 8d8faf68 rédigé par augier's avatar augier Validation de theworldbright
Parcourir les fichiers

OpenID Connect debut work

parent 2af02db0
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
......@@ -149,6 +149,9 @@ gem "omniauth-twitter", "1.2.1"
gem "twitter", "5.15.0"
gem "omniauth-wordpress", "0.2.2"
# OpenID Connect
gem "openid_connect"
# Serializers
gem "active_model_serializers", "0.9.3"
......
class AuthorizationsController < ApplicationController
rescue_from Rack::OAuth2::Server::Authorize::BadRequest do |e|
@error = e
logger.info e.backtrace[0,10].join("\n")
render :error, status: e.status
end
def new
call_authorization_endpoint
end
def create
call_authorization_endpoint :allow_approval, params[:approve]
end
private
def call_authorization_endpoint(allow_approval = false, approved = false)
endpoint = AuthorizationEndpoint.new allow_approval, approved
rack_response = *endpoint.call(request.env)
@client, @response_type, @redirect_uri, @scopes, @_request_, @request_uri, @request_object = *[
endpoint.client, endpoint.response_type, endpoint.redirect_uri, endpoint.scopes, endpoint._request_, endpoint.request_uri, endpoint.request_object
]
require_authentication
if (
!allow_approval &&
(max_age = @request_object.try(:id_token).try(:max_age)) &&
current_account.last_logged_in_at < max_age.seconds.ago
)
flash[:notice] = 'Exceeded Max Age, Login Again'
unauthenticate!
require_authentication
end
respond_as_rack_app *rack_response
end
def respond_as_rack_app(status, header, response)
["WWW-Authenticate"].each do |key|
headers[key] = header[key] if header[key].present?
end
if response.redirect?
redirect_to header['Location']
else
render :new
end
end
end
class ConnectController < ApplicationController
def show
end
end
class DiscoveryController < ApplicationController
def show
case params[:id]
when 'webfinger'
webfinger_discovery
when 'openid-configuration'
openid_configuration
else
raise HttpError::NotFound
end
end
private
def webfinger_discovery
jrd = {
links: [{
rel: OpenIDConnect::Discovery::Provider::Issuer::REL_VALUE,
href: "http://0.0.0.0:3000"
}]
}
jrd[:subject] = params[:resource] if params[:resource].present?
render json: jrd, content_type: "application/jrd+json"
end
def openid_configuration
config = OpenIDConnect::Discovery::Provider::Config::Response.new(
issuer: "http://0.0.0.0:3000",
authorization_endpoint: "#{authorizations_url}/new",
token_endpoint: access_tokens_url,
userinfo_endpoint: user_info_url,
jwks_uri: "#{authorizations_url}/jwks.json",
registration_endpoint: "http://0.0.0.0:3000/connect",
scopes_supported: "iss",
response_types_supported: "Client.available_response_types",
grant_types_supported: "Client.available_grant_types",
request_object_signing_alg_values_supported: [:HS256, :HS384, :HS512],
subject_types_supported: ['public', 'pairwise'],
id_token_signing_alg_values_supported: [:RS256],
token_endpoint_auth_methods_supported: ['client_secret_basic', 'client_secret_post'],
claims_supported: ['sub', 'iss', 'name', 'email']
)
render json: config
end
end
......@@ -240,4 +240,13 @@ Diaspora::Application.routes.draw do
# Startpage
root :to => 'home#show'
#OpenID Connect & OAuth
resource :openid do
resources :authorizations, only: [:new, :create]
match 'connect', to: 'connect#show', via: [:get, :post]
match '.well-known/:id', to: 'discovery#show' , :via => [:get, :post]
match 'user_info', to: 'user#show', :via => [:get, :post]
post 'access_tokens', to: proc { |env| TokenEndpoint.new.call(env) }
end
end
......@@ -419,7 +419,7 @@ ActiveRecord::Schema.define(version: 20151003142048) do
t.string "location", limit: 255
t.string "full_name", limit: 70
t.boolean "nsfw", default: false
t.boolean "public_details", default: false
t.boolean "public_details", default: false
end
add_index "profiles", ["full_name", "searchable"], name: "index_profiles_on_full_name_and_searchable", using: :btree
......
class AuthorizationEndpoint
attr_accessor :app, :account, :client, :redirect_uri, :response_type, :scopes, :_request_, :request_uri, :request_object
delegate :call, to: :app
def initialize(allow_approval = false, approved = false)
@account = nil
@app = Rack::OAuth2::Server::Authorize.new do |req, res|
@client = nil # Find the client
res.redirect_uri = @redirect_uri = req.verify_redirect_uri!(@client.redirect_uris)
if res.protocol_params_location == :fragment && req.nonce.blank?
req.invalid_request! 'nonce required'
end
@scopes = req.scope.inject([]) do |_scopes_, scope|
_scopes_ << Scope.find_by_name(scope) or req.invalid_scope! "Unknown scope: #{scope}"
end
@request_object = if (@_request_ = req.request).present?
OpenIDConnect::RequestObject.decode req.request, nil # @client.secret
elsif (@request_uri = req.request_uri).present?
OpenIDConnect::RequestObject.fetch req.request_uri, nil # @client.secret
end
if Client.available_response_types.include? Array(req.response_type).collect(&:to_s).join(' ')
if allow_approval
if approved
approved! req, res
else
req.access_denied!
end
else
@response_type = req.response_type
end
else
req.unsupported_response_type!
end
end
end
def approved!(req, res)
response_types = Array(req.response_type)
if response_types.include? :code
authorization = account.authorizations.create!(client: @client, redirect_uri: res.redirect_uri, nonce: req.nonce)
authorization.scopes << scopes
if @request_object
authorization.create_authorization_request_object!(
request_object: RequestObject.new(
jwt_string: @request_object.to_jwt(@client.secret, :HS256)
)
)
end
res.code = authorization.code
end
if response_types.include? :token
access_token = account.access_tokens.create!(client: @client)
access_token.scopes << scopes
if @request_object
access_token.create_access_token_request_object!(
request_object: RequestObject.new(
jwt_string: @request_object.to_jwt(@client.secret, :HS256)
)
)
end
res.access_token = access_token.to_bearer_token
end
if response_types.include? :id_token
_id_token_ = account.id_tokens.create!(
client: @client,
nonce: req.nonce
)
if @request_object
_id_token_.create_id_token_request_object!(
request_object: RequestObject.new(
jwt_string: @request_object.to_jwt(@client.secret, :HS256)
)
)
end
res.id_token = _id_token_.to_jwt(
code: (res.respond_to?(:code) ? res.code : nil),
access_token: (res.respond_to?(:access_token) ? res.access_token : nil)
)
end
res.approve!
end
end
\ No newline at end of file
class TokenEndpoint
attr_accessor :app
delegate :call, to: :app
def initialize
@app = Rack::OAuth2::Server::Token.new do |req, res|
client = Client.find_by_identifier(req.client_id) || req.invalid_client!
client.secret == req.client_secret || req.invalid_client!
case req.grant_type
when :client_credentials
res.access_token = client.access_tokens.create!.to_bearer_token
when :authorization_code
authorization = client.authorizations.valid.find_by_code(req.code)
req.invalid_grant! if authorization.blank? || !authorization.valid_redirect_uri?(req.redirect_uri)
access_token = authorization.access_token
res.access_token = access_token.to_bearer_token
if access_token.accessible?(Scope::OPENID)
res.id_token = access_token.account.id_tokens.create!(
client: access_token.client,
nonce: authorization.nonce,
request_object: authorization.request_object
).to_response_object.to_jwt IdToken.config[:private_key]
end
else
req.unsupported_grant_type!
end
end
end
end
\ No newline at end of file
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter