Commit d1db7b1b authored by Gabriel Mazetto's avatar Gabriel Mazetto

Adds support for authenticating in Geo secondary node using OAuth

parent b44c7df8
......@@ -102,7 +102,7 @@ class ApplicationController < ActionController::Base
flash[:alert] = "Your account is blocked. Retry when an admin has unblocked it."
new_user_session_path
else
stored_location_for(:geo_node) || stored_location_for(:redirect) || stored_location_for(resource) || root_path
stored_location_for(:redirect) || stored_location_for(resource) || root_path
end
end
......
......@@ -109,12 +109,13 @@ class SessionsController < Devise::SessionsController
def gitlab_geo_login
if !signed_in? && Gitlab::Geo.enabled? && Gitlab::Geo.secondary?
oauth = Geo::OauthSession.new
# share full url with primary node by shared session
user_return_to = URI.join(root_url, session[:user_return_to]).to_s
session[:geo_node_return_to] = @redirect_to || user_return_to
oauth.return_to = @redirect_to || user_return_to
login_uri = URI.join(Gitlab::Geo.primary_node.url, new_session_path(:user)).to_s
redirect_to login_uri
redirect_to oauth_geo_auth_url(state: oauth.generate_oauth_state)
end
end
......
class Geo::OauthSession
include ActiveModel::Model
include HTTParty
attr_accessor :state
attr_accessor :return_to
API_PREFIX = '/api/v3/'
def is_oauth_state_valid?
return true unless state
salt, hmac, return_to = state.split(':', 3)
return false unless return_to
hmac == self.generate_oauth_hmac(salt)
end
def generate_oauth_state
return unless return_to
salt = generate_oauth_salt
hmac = generate_oauth_hmac(salt)
"#{salt}:#{hmac}:#{return_to}"
end
def get_oauth_state_return_to
state.split(':', 3)[2] if state
end
def authenticate(access_token)
opts = {
query: access_token
}
endpoint = File.join(primary_node_url, API_PREFIX, 'user')
response = self.class.get(endpoint, default_opts.merge(opts))
build_response(response)
end
private
def generate_oauth_salt
SecureRandom.hex(16)
end
def generate_oauth_hmac(salt)
return unless return_to
digest = OpenSSL::Digest.new('sha256')
key = GitlabCi::Application.secrets.secret_key_base + salt
OpenSSL::HMAC.hexdigest(digest, key, return_to)
end
def primary_node_url
Gitlab::Geo.primary_node.url
end
def default_opts
{
headers: { 'Content-Type' => 'application/json' },
}
end
def build_response(response)
case response.code
when 200
response.parsed_response
when 401
raise UnauthorizedError
else
nil
end
end
end
......@@ -12,6 +12,7 @@
class GeoNode < ActiveRecord::Base
belongs_to :geo_node_key, dependent: :destroy
belongs_to :oauth_application, class_name: 'Doorkeeper::Application'
default_values schema: 'http',
host: lambda { Gitlab.config.gitlab.host },
......
......@@ -39,6 +39,11 @@ Rails.application.routes.draw do
authorizations: 'oauth/authorizations'
end
namespace :oauth do
get 'geo/auth' => 'geo_auth#auth'
get 'geo/callback' => 'geo_auth#callback'
end
# Autocomplete
get '/autocomplete/users' => 'autocomplete#users'
get '/autocomplete/users/:id' => 'autocomplete#user'
......
class AddDoorkeeperApplicationToGeoNode < ActiveRecord::Migration
def change
change_table :geo_nodes do |t|
t.belongs_to :oauth_application
end
end
end
......@@ -414,6 +414,7 @@ ActiveRecord::Schema.define(version: 20160309140734) do
t.string "relative_url_root"
t.boolean "primary"
t.integer "geo_node_key_id"
t.integer "oauth_application_id"
end
add_index "geo_nodes", ["geo_node_key_id"], name: "index_geo_nodes_on_geo_node_key_id", using: :btree
......
......@@ -39,5 +39,11 @@ module Gitlab
def self.bulk_notify_job
Sidekiq::Cron::Job.find('geo_bulk_notify_worker')
end
def self.oauth_authentication
return false unless self.readonly?
Gitlab::Geo.current_node.oauth_application
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment