Skip to content
Snippets Groups Projects
Commit 46b1b9c1 authored by Andreas Brandl's avatar Andreas Brandl
Browse files

Revert "Merge branch 'if-57131-external_auth_to_ce' into 'master'"

This reverts merge request !26823
parent 7a48a06c
No related branches found
No related tags found
No related merge requests found
Showing
with 9 additions and 347 deletions
Loading
Loading
@@ -67,10 +67,6 @@
}
}
 
.classification-label {
background-color: $red-500;
}
.toggle-wrapper {
margin-top: 5px;
}
Loading
Loading
Loading
Loading
@@ -124,9 +124,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
end
 
def visible_application_setting_attributes
[
*::ApplicationSettingsHelper.visible_attributes,
*::ApplicationSettingsHelper.external_authorization_service_attributes,
ApplicationSettingsHelper.visible_attributes + [
:domain_blacklist_file,
disabled_oauth_sign_in_sources: [],
import_sources: [],
Loading
Loading
# frozen_string_literal: true
 
module ProjectUnauthorized
def project_unauthorized_proc
lambda do |project|
if project
label = project.external_authorization_classification_label
rejection_reason = nil
unless ::Gitlab::ExternalAuthorization.access_allowed?(current_user, label)
rejection_reason = ::Gitlab::ExternalAuthorization.rejection_reason(current_user, label)
rejection_reason ||= _('External authorization denied access to this project')
end
extend ActiveSupport::Concern
 
if rejection_reason
access_denied!(rejection_reason)
end
end
end
# EE would override this
def project_unauthorized_proc
# no-op
end
end
Loading
Loading
@@ -343,7 +343,6 @@ class ProjectsController < Projects::ApplicationController
:container_registry_enabled,
:default_branch,
:description,
:external_authorization_classification_label,
:import_url,
:issues_tracker,
:issues_tracker_id,
Loading
Loading
Loading
Loading
@@ -119,39 +119,6 @@ module ApplicationSettingsHelper
options_for_select(options, selected)
end
 
def external_authorization_description
_("If enabled, access to projects will be validated on an external service"\
" using their classification label.")
end
def external_authorization_timeout_help_text
_("Time in seconds GitLab will wait for a response from the external "\
"service. When the service does not respond in time, access will be "\
"denied.")
end
def external_authorization_url_help_text
_("When leaving the URL blank, classification labels can still be "\
"specified without disabling cross project features or performing "\
"external authorization checks.")
end
def external_authorization_client_certificate_help_text
_("The X509 Certificate to use when mutual TLS is required to communicate "\
"with the external authorization service. If left blank, the server "\
"certificate is still validated when accessing over HTTPS.")
end
def external_authorization_client_key_help_text
_("The private key to use when a client certificate is provided. This value "\
"is encrypted at rest.")
end
def external_authorization_client_pass_help_text
_("The passphrase required to decrypt the private key. This is optional "\
"and the value is encrypted at rest.")
end
def visible_attributes
[
:admin_notification_email,
Loading
Loading
@@ -270,18 +237,6 @@ module ApplicationSettingsHelper
]
end
 
def external_authorization_service_attributes
[
:external_auth_client_cert,
:external_auth_client_key,
:external_auth_client_key_pass,
:external_authorization_service_default_label,
:external_authorization_service_enabled,
:external_authorization_service_timeout,
:external_authorization_service_url
]
end
def expanded_by_default?
Rails.env.test?
end
Loading
Loading
Loading
Loading
@@ -303,16 +303,6 @@ module ProjectsHelper
@path.present?
end
 
def external_classification_label_help_message
default_label = ::Gitlab::CurrentSettings.current_application_settings
.external_authorization_service_default_label
s_(
"ExternalAuthorizationService|When no classification label is set the "\
"default label `%{default_label}` will be used."
) % { default_label: default_label }
end
private
 
def get_project_nav_tabs(project, current_user)
Loading
Loading
Loading
Loading
@@ -213,40 +213,6 @@ class ApplicationSetting < ApplicationRecord
 
validate :terms_exist, if: :enforce_terms?
 
validates :external_authorization_service_default_label,
presence: true,
if: :external_authorization_service_enabled
validates :external_authorization_service_url,
url: true, allow_blank: true,
if: :external_authorization_service_enabled
validates :external_authorization_service_timeout,
numericality: { greater_than: 0, less_than_or_equal_to: 10 },
if: :external_authorization_service_enabled
validates :external_auth_client_key,
presence: true,
if: -> (setting) { setting.external_auth_client_cert.present? }
validates_with X509CertificateCredentialsValidator,
certificate: :external_auth_client_cert,
pkey: :external_auth_client_key,
pass: :external_auth_client_key_pass,
if: -> (setting) { setting.external_auth_client_cert.present? }
attr_encrypted :external_auth_client_key,
mode: :per_attribute_iv,
key: Settings.attr_encrypted_db_key_base_truncated,
algorithm: 'aes-256-gcm',
encode: true
attr_encrypted :external_auth_client_key_pass,
mode: :per_attribute_iv,
key: Settings.attr_encrypted_db_key_base_truncated,
algorithm: 'aes-256-gcm',
encode: true
before_validation :ensure_uuid!
before_validation :strip_sentry_values
 
Loading
Loading
Loading
Loading
@@ -230,13 +230,7 @@ class Issue < ApplicationRecord
def visible_to_user?(user = nil)
return false unless project && project.feature_available?(:issues, user)
 
return publicly_visible? unless user
return false unless readable_by?(user)
user.full_private_access? ||
::Gitlab::ExternalAuthorization.access_allowed?(
user, project.external_authorization_classification_label)
user ? readable_by?(user) : publicly_visible?
end
 
def check_for_spam?
Loading
Loading
@@ -304,7 +298,7 @@ class Issue < ApplicationRecord
 
# Returns `true` if this Issue is visible to everybody.
def publicly_visible?
project.public? && !confidential? && !::Gitlab::ExternalAuthorization.enabled?
project.public? && !confidential?
end
 
def expire_etag_cache
Loading
Loading
Loading
Loading
@@ -2062,11 +2062,6 @@ class Project < ApplicationRecord
fetch_branch_allows_collaboration(user, branch_name)
end
 
def external_authorization_classification_label
super || ::Gitlab::CurrentSettings.current_application_settings
.external_authorization_service_default_label
end
def licensed_features
[]
end
Loading
Loading
Loading
Loading
@@ -22,13 +22,6 @@ class BasePolicy < DeclarativePolicy::Base
Gitlab::CurrentSettings.current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC)
end
 
condition(:external_authorization_enabled, scope: :global, score: 0) do
::Gitlab::ExternalAuthorization.perform_check?
end
rule { external_authorization_enabled & ~full_private_access }.policy do
prevent :read_cross_project
end
# This is prevented in some cases in `gitlab-ee`
rule { default }.enable :read_cross_project
end
Loading
Loading
@@ -89,15 +89,6 @@ class ProjectPolicy < BasePolicy
::Gitlab::CurrentSettings.current_application_settings.mirror_available
end
 
with_scope :subject
condition(:classification_label_authorized, score: 32) do
::Gitlab::ExternalAuthorization.access_allowed?(
@user,
@subject.external_authorization_classification_label,
@subject.full_path
)
end
# We aren't checking `:read_issue` or `:read_merge_request` in this case
# because it could be possible for a user to see an issuable-iid
# (`:read_issue_iid` or `:read_merge_request_iid`) but then wouldn't be
Loading
Loading
@@ -426,25 +417,6 @@ class ProjectPolicy < BasePolicy
 
rule { ~can_have_multiple_clusters & has_clusters }.prevent :add_cluster
 
rule { ~can?(:read_cross_project) & ~classification_label_authorized }.policy do
# Preventing access here still allows the projects to be listed. Listing
# projects doesn't check the `:read_project` ability. But instead counts
# on the `project_authorizations` table.
#
# All other actions should explicitly check read project, which would
# trigger the `classification_label_authorized` condition.
#
# `:read_project_for_iids` is not prevented by this condition, as it is
# used for cross-project reference checks.
prevent :guest_access
prevent :public_access
prevent :public_user_access
prevent :reporter_access
prevent :developer_access
prevent :maintainer_access
prevent :owner_access
end
private
 
def team_member?
Loading
Loading
Loading
Loading
@@ -2,17 +2,9 @@
 
module ApplicationSettings
class UpdateService < ApplicationSettings::BaseService
include ValidatesClassificationLabel
attr_reader :params, :application_setting
 
def execute
validate_classification_label(application_setting, :external_authorization_service_default_label)
if application_setting.errors.any?
return false
end
update_terms(@params.delete(:terms))
 
if params.key?(:performance_bar_allowed_group_path)
Loading
Loading
# frozen_string_literal: true
module ValidatesClassificationLabel
def validate_classification_label(record, attribute_name)
return unless ::Gitlab::ExternalAuthorization.enabled?
return unless classification_label_change?(record, attribute_name)
new_label = params[attribute_name].presence
new_label ||= ::Gitlab::CurrentSettings.current_application_settings
.external_authorization_service_default_label
unless ::Gitlab::ExternalAuthorization.access_allowed?(current_user, new_label)
reason = rejection_reason_for_label(new_label)
message = s_('ClassificationLabelUnavailable|is unavailable: %{reason}') % { reason: reason }
record.errors.add(attribute_name, message)
end
end
def rejection_reason_for_label(label)
reason_from_service = ::Gitlab::ExternalAuthorization.rejection_reason(current_user, label).presence
reason_from_service || _("Access to '%{classification_label}' not allowed") % { classification_label: label }
end
def classification_label_change?(record, attribute_name)
params.key?(attribute_name) || record.new_record?
end
end
Loading
Loading
@@ -2,8 +2,6 @@
 
module Projects
class CreateService < BaseService
include ValidatesClassificationLabel
def initialize(user, params)
@current_user, @params = user, params.dup
@skip_wiki = @params.delete(:skip_wiki)
Loading
Loading
@@ -47,8 +45,6 @@ module Projects
relations_block&.call(@project)
yield(@project) if block_given?
 
validate_classification_label(@project, :external_authorization_classification_label)
# If the block added errors, don't try to save the project
return @project if @project.errors.any?
 
Loading
Loading
Loading
Loading
@@ -3,7 +3,6 @@
module Projects
class UpdateService < BaseService
include UpdateVisibilityLevel
include ValidatesClassificationLabel
 
ValidationError = Class.new(StandardError)
 
Loading
Loading
@@ -15,8 +14,6 @@ module Projects
 
yield if block_given?
 
validate_classification_label(project, :external_authorization_classification_label)
# If the block added errors, don't try to save the project
return update_failed! if project.errors.any?
 
Loading
Loading
# frozen_string_literal: true
# X509CertificateCredentialsValidator
#
# Custom validator to check if certificate-attribute was signed using the
# private key stored in an attrebute.
#
# This can be used as an `ActiveModel::Validator` as follows:
#
# validates_with X509CertificateCredentialsValidator,
# certificate: :client_certificate,
# pkey: :decrypted_private_key,
# pass: :decrypted_passphrase
#
#
# Required attributes:
# - certificate: The name of the accessor that returns the certificate to check
# - pkey: The name of the accessor that returns the private key
# Optional:
# - pass: The name of the accessor that returns the passphrase to decrypt the
# private key
class X509CertificateCredentialsValidator < ActiveModel::Validator
def initialize(*args)
super
# We can't validate if we don't have a private key or certificate attributes
# in which case this validator is useless.
if options[:pkey].nil? || options[:certificate].nil?
raise 'Provide at least `certificate` and `pkey` attribute names'
end
end
def validate(record)
unless certificate = read_certificate(record)
record.errors.add(options[:certificate], _('is not a valid X509 certificate.'))
end
unless private_key = read_private_key(record)
record.errors.add(options[:pkey], _('could not read private key, is the passphrase correct?'))
end
return if private_key.nil? || certificate.nil?
unless certificate.public_key.fingerprint == private_key.public_key.fingerprint
record.errors.add(options[:pkey], _('private key does not match certificate.'))
end
end
private
def read_private_key(record)
OpenSSL::PKey.read(pkey(record).to_s, pass(record).to_s)
rescue OpenSSL::PKey::PKeyError, ArgumentError
# When the primary key could not be read, an ArgumentError is raised.
# This hapens when the passed key is not valid or the passphrase is incorrect
nil
end
def read_certificate(record)
OpenSSL::X509::Certificate.new(certificate(record).to_s)
rescue OpenSSL::X509::CertificateError
nil
end
# rubocop:disable GitlabSecurity/PublicSend
#
# Allowing `#public_send` here because we don't want the validator to really
# care about the names of the attributes or where they come from.
#
# The credentials are mostly stored encrypted so we need to go through the
# accessors to get the values, `read_attribute` bypasses those.
def certificate(record)
record.public_send(options[:certificate])
end
def pkey(record)
record.public_send(options[:pkey])
end
def pass(record)
return unless options[:pass]
record.public_send(options[:pass])
end
# rubocop:enable GitlabSecurity/PublicSend
end
%section.settings.as-external-auth.no-animate#js-external-auth-settings{ class: ('expanded' if expanded) }
.settings-header
%h4
= _('External authentication')
%button.btn.js-settings-toggle{ type: 'button' }
= expanded ? 'Collapse' : 'Expand'
%p
= _('External Classification Policy Authorization')
.settings-content
= form_for @application_setting, url: admin_application_settings_path(anchor: 'js-external-auth-settings'), html: { class: 'fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
.form-group
.form-check
= f.check_box :external_authorization_service_enabled, class: 'form-check-input'
= f.label :external_authorization_service_enabled, class: 'form-check-label' do
= _('Enable classification control using an external service')
%span.form-text.text-muted
= external_authorization_description
= link_to icon('question-circle'), help_page_path('user/admin_area/settings/external_authorization')
.form-group
= f.label :external_authorization_service_url, _('Service URL'), class: 'label-bold'
= f.text_field :external_authorization_service_url, class: 'form-control'
%span.form-text.text-muted
= external_authorization_url_help_text
.form-group
= f.label :external_authorization_service_timeout, _('External authorization request timeout'), class: 'label-bold'
= f.number_field :external_authorization_service_timeout, class: 'form-control', min: 0.001, max: 10, step: 0.001
%span.form-text.text-muted
= external_authorization_timeout_help_text
= f.label :external_auth_client_cert, _('Client authentication certificate'), class: 'label-bold'
= f.text_area :external_auth_client_cert, class: 'form-control'
%span.form-text.text-muted
= external_authorization_client_certificate_help_text
.form-group
= f.label :external_auth_client_key, _('Client authentication key'), class: 'label-bold'
= f.text_area :external_auth_client_key, class: 'form-control'
%span.form-text.text-muted
= external_authorization_client_key_help_text
.form-group
= f.label :external_auth_client_key_pass, _('Client authentication key password'), class: 'label-bold'
= f.password_field :external_auth_client_key_pass, class: 'form-control'
%span.form-text.text-muted
= external_authorization_client_pass_help_text
.form-group
= f.label :external_authorization_service_default_label, _('Default classification label'), class: 'label-bold'
= f.text_field :external_authorization_service_default_label, class: 'form-control'
= f.submit 'Save changes', class: "btn btn-success"
Loading
Loading
@@ -68,7 +68,7 @@
.settings-content
= render 'terms'
 
= render 'admin/application_settings/external_authorization_service_form', expanded: expanded_by_default?
= render_if_exists 'admin/application_settings/external_authorization_service_form', expanded: expanded_by_default?
 
%section.settings.as-terminal.no-animate#js-terminal-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
Loading
Loading
Loading
Loading
@@ -7,7 +7,6 @@
.alert-wrapper
= render "layouts/broadcast"
= render "layouts/header/read_only_banner"
= render "layouts/nav/classification_level_banner"
= yield :flash_message
= render "shared/ping_consent"
- unless @hide_breadcrumbs
Loading
Loading
- if ::Gitlab::ExternalAuthorization.enabled? && @project
= content_for :header_content do
%span.badge.color-label.classification-label.has-tooltip{ title: s_('ExternalAuthorizationService|Classification label') }
= sprite_icon('lock-open', size: 8, css_class: 'inline')
= @project.external_authorization_classification_label
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment