debian-mirror-gitlab/lib/mattermost/session.rb

194 lines
4.8 KiB
Ruby
Raw Normal View History

2018-12-13 13:39:08 +05:30
# frozen_string_literal: true
2017-08-17 22:00:37 +05:30
module Mattermost
2021-09-04 01:27:46 +05:30
class NoSessionError < ::Mattermost::Error
2017-08-17 22:00:37 +05:30
def message
'No session could be set up, is Mattermost configured with Single Sign On?'
end
end
2021-09-04 01:27:46 +05:30
ConnectionError = Class.new(::Mattermost::Error)
2017-08-17 22:00:37 +05:30
# This class' prime objective is to obtain a session token on a Mattermost
# instance with SSO configured where this GitLab instance is the provider.
#
# The process depends on OAuth, but skips a step in the authentication cycle.
# For example, usually a user would click the 'login in GitLab' button on
# Mattermost, which would yield a 302 status code and redirects you to GitLab
# to approve the use of your account on Mattermost. Which would trigger a
# callback so Mattermost knows this request is approved and gets the required
# data to create the user account etc.
#
# This class however skips the button click, and also the approval phase to
# speed up the process and keep it without manual action and get a session
# going.
class Session
include Doorkeeper::Helpers::Controller
LEASE_TIMEOUT = 60
2022-06-21 17:19:12 +05:30
Request = Struct.new(:parameters, keyword_init: true) do
def method_missing(method_name, *args, &block)
end
end
2018-03-26 14:24:53 +05:30
attr_accessor :current_resource_owner, :token, :base_uri
2017-08-17 22:00:37 +05:30
def initialize(current_user)
@current_resource_owner = current_user
2018-03-26 14:24:53 +05:30
@base_uri = Settings.mattermost.host
2017-08-17 22:00:37 +05:30
end
def with_session
with_lease do
2017-09-10 17:25:29 +05:30
create
2017-08-17 22:00:37 +05:30
begin
yield self
2017-09-10 17:25:29 +05:30
rescue Errno::ECONNREFUSED => e
2020-11-24 15:15:51 +05:30
Gitlab::AppLogger.error(e.message + "\n" + e.backtrace.join("\n"))
2021-09-04 01:27:46 +05:30
raise ::Mattermost::NoSessionError
2017-08-17 22:00:37 +05:30
ensure
destroy
end
end
end
# Next methods are needed for Doorkeeper
def pre_auth
@pre_auth ||= Doorkeeper::OAuth::PreAuthorization.new(
2020-11-24 15:15:51 +05:30
Doorkeeper.configuration, params)
2017-08-17 22:00:37 +05:30
end
def authorization
@authorization ||= strategy.request
end
def strategy
@strategy ||= server.authorization_request(pre_auth.response_type)
end
def request
2022-06-21 17:19:12 +05:30
@request ||= Request.new(parameters: params)
2017-08-17 22:00:37 +05:30
end
def params
Rack::Utils.parse_query(oauth_uri.query).symbolize_keys
end
def get(path, options = {})
handle_exceptions do
2018-03-26 14:24:53 +05:30
Gitlab::HTTP.get(path, build_options(options))
2017-08-17 22:00:37 +05:30
end
end
def post(path, options = {})
handle_exceptions do
2018-03-26 14:24:53 +05:30
Gitlab::HTTP.post(path, build_options(options))
2017-08-17 22:00:37 +05:30
end
end
2018-05-09 12:01:36 +05:30
def delete(path, options = {})
handle_exceptions do
Gitlab::HTTP.delete(path, build_options(options))
end
end
2017-08-17 22:00:37 +05:30
private
2018-03-26 14:24:53 +05:30
def build_options(options)
options.tap do |hash|
hash[:headers] = @headers
hash[:allow_local_requests] = true
hash[:base_uri] = base_uri if base_uri.presence
end
end
2017-08-17 22:00:37 +05:30
def create
2021-09-04 01:27:46 +05:30
raise ::Mattermost::NoSessionError unless oauth_uri
raise ::Mattermost::NoSessionError unless token_uri
2017-08-17 22:00:37 +05:30
@token = request_token
2021-09-04 01:27:46 +05:30
raise ::Mattermost::NoSessionError unless @token
2017-09-10 17:25:29 +05:30
2017-08-17 22:00:37 +05:30
@headers = {
Authorization: "Bearer #{@token}"
}
@token
end
def destroy
2018-11-08 19:23:39 +05:30
post('/api/v4/users/logout')
2017-08-17 22:00:37 +05:30
end
def oauth_uri
return @oauth_uri if defined?(@oauth_uri)
@oauth_uri = nil
2019-09-04 21:01:54 +05:30
response = get('/oauth/gitlab/login', follow_redirects: false)
2017-09-10 17:25:29 +05:30
return unless (300...400) === response.code
2017-08-17 22:00:37 +05:30
redirect_uri = response.headers['location']
return unless redirect_uri
2017-09-10 17:25:29 +05:30
oauth_cookie = parse_cookie(response)
@headers = {
Cookie: oauth_cookie.to_cookie_string
}
2017-08-17 22:00:37 +05:30
@oauth_uri = URI.parse(redirect_uri)
end
def token_uri
@token_uri ||=
if oauth_uri
authorization.authorize.redirect_uri if pre_auth.authorizable?
end
end
def request_token
response = get(token_uri, follow_redirects: false)
2017-09-10 17:25:29 +05:30
if (200...400) === response.code
2017-08-17 22:00:37 +05:30
response.headers['token']
end
end
def with_lease
lease_uuid = lease_try_obtain
raise NoSessionError unless lease_uuid
begin
yield
ensure
Gitlab::ExclusiveLease.cancel(lease_key, lease_uuid)
end
end
def lease_key
"mattermost:session"
end
def lease_try_obtain
lease = ::Gitlab::ExclusiveLease.new(lease_key, timeout: LEASE_TIMEOUT)
lease.try_obtain
end
def handle_exceptions
yield
2018-03-26 14:24:53 +05:30
rescue Gitlab::HTTP::Error => e
2021-09-04 01:27:46 +05:30
raise ::Mattermost::ConnectionError, e.message
2017-08-17 22:00:37 +05:30
rescue Errno::ECONNREFUSED => e
2021-09-04 01:27:46 +05:30
raise ::Mattermost::ConnectionError, e.message
2017-08-17 22:00:37 +05:30
end
2017-09-10 17:25:29 +05:30
def parse_cookie(response)
2018-03-26 14:24:53 +05:30
cookie_hash = Gitlab::HTTP::CookieHash.new
2017-09-10 17:25:29 +05:30
response.get_fields('Set-Cookie').each { |c| cookie_hash.add_cookies(c) }
cookie_hash
end
2017-08-17 22:00:37 +05:30
end
end