diff options
author | Grzegorz Bizon <grzesiek.bizon@gmail.com> | 2016-06-10 10:49:07 +0200 |
---|---|---|
committer | Grzegorz Bizon <grzesiek.bizon@gmail.com> | 2016-06-10 10:49:07 +0200 |
commit | 51046dd22628cc54e92ca6da016c05762158e8ea (patch) | |
tree | a9352e9e0be4b74ee2622d85ee93a10e748fb225 /lib | |
parent | d7e125116124b9c08c27b4a02f4738619db1d2f5 (diff) | |
parent | cea3cf177c68bb1fa9326d4e88631b7737ae8a98 (diff) | |
download | gitlab-ce-51046dd22628cc54e92ca6da016c05762158e8ea.tar.gz |
Merge branch 'master' into refactor/ci-config-add-global-entry
* master: (147 commits)
Minor MR comment fixes.
Update CHANGELOG for 8.8.4 and 8.8.5
Properly quote table name in Rake task for MySQL and PostgreSQL compatibility
Checks based on whether data is loaded not undefined
Checks for undefined when inserting autocomplete into textarea
Ignore frequent emojis in search.
Fixed tests
CHANGELOG
Improved the UX of issue & milestone date picker
Change date format to be non zero padded in order to fix failing test
Update method name for better understanding
Add tests for dates on tooltips
Fix local timeago on user dashboard
Update CHANGELOG
Toggling a task in a description with mentions doesn't creates a Todo
Update CHANGELOG
Fixed failing label subscribe test
Tests update
Updated subscribe icon
Fixed failing tests
...
Diffstat (limited to 'lib')
-rw-r--r-- | lib/api/entities.rb | 1 | ||||
-rw-r--r-- | lib/api/issues.rb | 4 | ||||
-rw-r--r-- | lib/api/merge_requests.rb | 2 | ||||
-rw-r--r-- | lib/api/session.rb | 3 | ||||
-rw-r--r-- | lib/banzai/filter/external_link_filter.rb | 1 | ||||
-rw-r--r-- | lib/banzai/filter/wiki_link_filter.rb | 32 | ||||
-rw-r--r-- | lib/banzai/filter/wiki_link_filter/rewriter.rb | 40 | ||||
-rw-r--r-- | lib/gitlab/auth.rb | 95 | ||||
-rw-r--r-- | lib/gitlab/auth/ip_rate_limiter.rb | 42 | ||||
-rw-r--r-- | lib/gitlab/backend/grack_auth.rb | 55 | ||||
-rw-r--r-- | lib/gitlab/current_settings.rb | 5 | ||||
-rw-r--r-- | lib/gitlab/github_import/importer.rb | 1 | ||||
-rw-r--r-- | lib/gitlab/gon_helper.rb | 1 | ||||
-rw-r--r-- | lib/gitlab/o_auth/user.rb | 17 | ||||
-rw-r--r-- | lib/gitlab/saml/user.rb | 4 | ||||
-rw-r--r-- | lib/gitlab/workhorse.rb | 7 | ||||
-rw-r--r-- | lib/tasks/gitlab/db.rake | 2 |
17 files changed, 206 insertions, 106 deletions
diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 66c138eb902..50d69274b2e 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -351,6 +351,7 @@ module API expose :signin_enabled expose :gravatar_enabled expose :sign_in_text + expose :after_sign_up_text expose :created_at expose :updated_at expose :home_page_url diff --git a/lib/api/issues.rb b/lib/api/issues.rb index f59a4d6c012..4c43257c48a 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -51,7 +51,7 @@ module API # GET /issues?labels=foo,bar # GET /issues?labels=foo,bar&state=opened get do - issues = current_user.issues + issues = current_user.issues.inc_notes_with_associations issues = filter_issues_state(issues, params[:state]) unless params[:state].nil? issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil? issues.reorder(issuable_order_by => issuable_sort) @@ -82,7 +82,7 @@ module API # GET /projects/:id/issues?milestone=1.0.0&state=closed # GET /issues?iid=42 get ":id/issues" do - issues = user_project.issues.visible_to_user(current_user) + issues = user_project.issues.inc_notes_with_associations.visible_to_user(current_user) issues = filter_issues_state(issues, params[:state]) unless params[:state].nil? issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil? issues = filter_by_iid(issues, params[:iid]) unless params[:iid].nil? diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 2e7836dc8fb..43221d5622a 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -41,7 +41,7 @@ module API # get ":id/merge_requests" do authorize! :read_merge_request, user_project - merge_requests = user_project.merge_requests + merge_requests = user_project.merge_requests.inc_notes_with_associations unless params[:iid].nil? merge_requests = filter_by_iid(merge_requests, params[:iid]) diff --git a/lib/api/session.rb b/lib/api/session.rb index cc646895914..56e69b2366f 100644 --- a/lib/api/session.rb +++ b/lib/api/session.rb @@ -11,8 +11,7 @@ module API # Example Request: # POST /session post "/session" do - auth = Gitlab::Auth.new - user = auth.find(params[:email] || params[:login], params[:password]) + user = Gitlab::Auth.find_in_gitlab_or_ldap(params[:email] || params[:login], params[:password]) return unauthorized! unless user present user, with: Entities::UserLogin diff --git a/lib/banzai/filter/external_link_filter.rb b/lib/banzai/filter/external_link_filter.rb index 38c4219518e..f73ecfc9418 100644 --- a/lib/banzai/filter/external_link_filter.rb +++ b/lib/banzai/filter/external_link_filter.rb @@ -15,6 +15,7 @@ module Banzai next if link.start_with?(internal_url) node.set_attribute('rel', 'nofollow noreferrer') + node.set_attribute('target', '_blank') end doc diff --git a/lib/banzai/filter/wiki_link_filter.rb b/lib/banzai/filter/wiki_link_filter.rb index 7dc771afd71..37a2779d453 100644 --- a/lib/banzai/filter/wiki_link_filter.rb +++ b/lib/banzai/filter/wiki_link_filter.rb @@ -2,7 +2,8 @@ require 'uri' module Banzai module Filter - # HTML filter that "fixes" relative links to files in a repository. + # HTML filter that "fixes" links to pages/files in a wiki. + # Rewrite rules are documented in the `WikiPipeline` spec. # # Context options: # :project_wiki @@ -25,36 +26,15 @@ module Banzai end def process_link_attr(html_attr) - return if html_attr.blank? || file_reference?(html_attr) || hierarchical_link?(html_attr) + return if html_attr.blank? - uri = URI(html_attr.value) - if uri.relative? && uri.path.present? - html_attr.value = rebuild_wiki_uri(uri).to_s - end + html_attr.value = apply_rewrite_rules(html_attr.value) rescue URI::Error # noop end - def rebuild_wiki_uri(uri) - uri.path = ::File.join(project_wiki_base_path, uri.path) - uri - end - - def project_wiki - context[:project_wiki] - end - - def file_reference?(html_attr) - !File.extname(html_attr.value).blank? - end - - # Of the form `./link`, `../link`, or similar - def hierarchical_link?(html_attr) - html_attr.value[0] == '.' - end - - def project_wiki_base_path - project_wiki && project_wiki.wiki_base_path + def apply_rewrite_rules(link_string) + Rewriter.new(link_string, wiki: context[:project_wiki], slug: context[:page_slug]).apply_rules end end end diff --git a/lib/banzai/filter/wiki_link_filter/rewriter.rb b/lib/banzai/filter/wiki_link_filter/rewriter.rb new file mode 100644 index 00000000000..2e2c8da311e --- /dev/null +++ b/lib/banzai/filter/wiki_link_filter/rewriter.rb @@ -0,0 +1,40 @@ +module Banzai + module Filter + class WikiLinkFilter < HTML::Pipeline::Filter + class Rewriter + def initialize(link_string, wiki:, slug:) + @uri = Addressable::URI.parse(link_string) + @wiki_base_path = wiki && wiki.wiki_base_path + @slug = slug + end + + def apply_rules + apply_file_link_rules! + apply_hierarchical_link_rules! + apply_relative_link_rules! + @uri.to_s + end + + private + + # Of the form 'file.md' + def apply_file_link_rules! + @uri = Addressable::URI.join(@slug, @uri) if @uri.extname.present? + end + + # Of the form `./link`, `../link`, or similar + def apply_hierarchical_link_rules! + @uri = Addressable::URI.join(@slug, @uri) if @uri.to_s[0] == '.' + end + + # Any link _not_ of the form `http://example.com/` + def apply_relative_link_rules! + if @uri.relative? && @uri.path.present? + link = ::File.join(@wiki_base_path, @uri.path) + @uri = Addressable::URI.parse(link) + end + end + end + end + end +end diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb index 30509528b8b..076e2af7d38 100644 --- a/lib/gitlab/auth.rb +++ b/lib/gitlab/auth.rb @@ -1,17 +1,86 @@ module Gitlab - class Auth - def find(login, password) - user = User.by_login(login) - - # If no user is found, or it's an LDAP server, try LDAP. - # LDAP users are only authenticated via LDAP - if user.nil? || user.ldap_user? - # Second chance - try LDAP authentication - return nil unless Gitlab::LDAP::Config.enabled? - - Gitlab::LDAP::Authentication.login(login, password) - else - user if user.valid_password?(password) + module Auth + Result = Struct.new(:user, :type) + + class << self + def find(login, password, project:, ip:) + raise "Must provide an IP for rate limiting" if ip.nil? + + result = Result.new + + if valid_ci_request?(login, password, project) + result.type = :ci + elsif result.user = find_in_gitlab_or_ldap(login, password) + result.type = :gitlab_or_ldap + elsif result.user = oauth_access_token_check(login, password) + result.type = :oauth + end + + rate_limit!(ip, success: !!result.user || (result.type == :ci), login: login) + result + end + + def find_in_gitlab_or_ldap(login, password) + user = User.by_login(login) + + # If no user is found, or it's an LDAP server, try LDAP. + # LDAP users are only authenticated via LDAP + if user.nil? || user.ldap_user? + # Second chance - try LDAP authentication + return nil unless Gitlab::LDAP::Config.enabled? + + Gitlab::LDAP::Authentication.login(login, password) + else + user if user.valid_password?(password) + end + end + + def rate_limit!(ip, success:, login:) + rate_limiter = Gitlab::Auth::IpRateLimiter.new(ip) + return unless rate_limiter.enabled? + + if success + # Repeated login 'failures' are normal behavior for some Git clients so + # it is important to reset the ban counter once the client has proven + # they are not a 'bad guy'. + rate_limiter.reset! + else + # Register a login failure so that Rack::Attack can block the next + # request from this IP if needed. + rate_limiter.register_fail! + + if rate_limiter.banned? + Rails.logger.info "IP #{ip} failed to login " \ + "as #{login} but has been temporarily banned from Git auth" + end + end + end + + private + + def valid_ci_request?(login, password, project) + matched_login = /(?<service>^[a-zA-Z]*-ci)-token$/.match(login) + + return false unless project && matched_login.present? + + underscored_service = matched_login['service'].underscore + + if underscored_service == 'gitlab_ci' + project && project.valid_build_token?(password) + elsif Service.available_services_names.include?(underscored_service) + # We treat underscored_service as a trusted input because it is included + # in the Service.available_services_names whitelist. + service = project.public_send("#{underscored_service}_service") + + service && service.activated? && service.valid_token?(password) + end + end + + def oauth_access_token_check(login, password) + if login == "oauth2" && password.present? + token = Doorkeeper::AccessToken.by_token(password) + token && token.accessible? && User.find_by(id: token.resource_owner_id) + end end end end diff --git a/lib/gitlab/auth/ip_rate_limiter.rb b/lib/gitlab/auth/ip_rate_limiter.rb new file mode 100644 index 00000000000..1089bc9f89e --- /dev/null +++ b/lib/gitlab/auth/ip_rate_limiter.rb @@ -0,0 +1,42 @@ +module Gitlab + module Auth + class IpRateLimiter + attr_reader :ip + + def initialize(ip) + @ip = ip + @banned = false + end + + def enabled? + config.enabled + end + + def reset! + Rack::Attack::Allow2Ban.reset(ip, config) + end + + def register_fail! + # Allow2Ban.filter will return false if this IP has not failed too often yet + @banned = Rack::Attack::Allow2Ban.filter(ip, config) do + # If we return false here, the failure for this IP is ignored by Allow2Ban + ip_can_be_banned? + end + end + + def banned? + @banned + end + + private + + def config + Gitlab.config.rack_attack.git_basic_auth + end + + def ip_can_be_banned? + config.ip_whitelist.exclude?(ip) + end + end + end +end diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb index cdcaae8094c..9e09d2e118d 100644 --- a/lib/gitlab/backend/grack_auth.rb +++ b/lib/gitlab/backend/grack_auth.rb @@ -36,10 +36,7 @@ module Grack lfs_response = Gitlab::Lfs::Router.new(project, @user, @request).try_call return lfs_response unless lfs_response.nil? - if project && authorized_request? - # Tell gitlab-workhorse the request is OK, and what the GL_ID is - render_grack_auth_ok - elsif @user.nil? && !@ci + if @user.nil? && !@ci unauthorized else render_not_found @@ -98,7 +95,7 @@ module Grack end def authenticate_user(login, password) - user = Gitlab::Auth.new.find(login, password) + user = Gitlab::Auth.find_in_gitlab_or_ldap(login, password) unless user user = oauth_access_token_check(login, password) @@ -141,36 +138,6 @@ module Grack user end - def authorized_request? - return true if @ci - - case git_cmd - when *Gitlab::GitAccess::DOWNLOAD_COMMANDS - if !Gitlab.config.gitlab_shell.upload_pack - false - elsif user - Gitlab::GitAccess.new(user, project).download_access_check.allowed? - elsif project.public? - # Allow clone/fetch for public projects - true - else - false - end - when *Gitlab::GitAccess::PUSH_COMMANDS - if !Gitlab.config.gitlab_shell.receive_pack - false - elsif user - # Skip user authorization on upload request. - # It will be done by the pre-receive hook in the repository. - true - else - false - end - else - false - end - end - def git_cmd if @request.get? @request.params['service'] @@ -197,24 +164,6 @@ module Grack end end - def render_grack_auth_ok - repo_path = - if @request.path_info =~ /^([\w\.\/-]+)\.wiki\.git/ - ProjectWiki.new(project).repository.path_to_repo - else - project.repository.path_to_repo - end - - [ - 200, - { "Content-Type" => "application/json" }, - [JSON.dump({ - 'GL_ID' => Gitlab::ShellEnv.gl_id(@user), - 'RepoPath' => repo_path, - })] - ] - end - def render_not_found [404, { "Content-Type" => "text/plain" }, ["Not Found"]] end diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb index 92c7e8b9d88..5e7532f57ae 100644 --- a/lib/gitlab/current_settings.rb +++ b/lib/gitlab/current_settings.rb @@ -26,7 +26,10 @@ module Gitlab signup_enabled: Settings.gitlab['signup_enabled'], signin_enabled: Settings.gitlab['signin_enabled'], gravatar_enabled: Settings.gravatar['enabled'], - sign_in_text: Settings.extra['sign_in_text'], + sign_in_text: nil, + after_sign_up_text: nil, + help_page_text: nil, + shared_runners_text: nil, restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'], max_attachment_size: Settings.gitlab['max_attachment_size'], session_expire_delay: Settings.gitlab['session_expire_delay'], diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb index 442b4c389fe..5ef9d66ba68 100644 --- a/lib/gitlab/github_import/importer.rb +++ b/lib/gitlab/github_import/importer.rb @@ -146,6 +146,7 @@ module Gitlab def update_webhooks(hooks, options) hooks.each do |hook| + sleep rate_limit_sleep_time if rate_limit_exceed? client.edit_hook(repo, hook.id, hook.name, hook.config, options) end end diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb index ab900b641c4..f751a3a12fd 100644 --- a/lib/gitlab/gon_helper.rb +++ b/lib/gitlab/gon_helper.rb @@ -8,6 +8,7 @@ module Gitlab gon.relative_url_root = Gitlab.config.gitlab.relative_url_root gon.shortcuts_path = help_shortcuts_path gon.user_color_scheme = Gitlab::ColorSchemes.for_user(current_user).css_class + gon.award_menu_url = emojis_path if current_user gon.current_user_id = current_user.id diff --git a/lib/gitlab/o_auth/user.rb b/lib/gitlab/o_auth/user.rb index 356e96fcbab..78f3ecb4cb4 100644 --- a/lib/gitlab/o_auth/user.rb +++ b/lib/gitlab/o_auth/user.rb @@ -69,13 +69,20 @@ module Gitlab return unless ldap_person # If a corresponding person exists with same uid in a LDAP server, - # set up a Gitlab user with dual LDAP and Omniauth identities. - if user = Gitlab::LDAP::User.find_by_uid_and_provider(ldap_person.dn, ldap_person.provider) - # Case when a LDAP user already exists in Gitlab. Add the Omniauth identity to existing account. + # check if the user already has a GitLab account. + user = Gitlab::LDAP::User.find_by_uid_and_provider(ldap_person.dn, ldap_person.provider) + if user + # Case when a LDAP user already exists in Gitlab. Add the OAuth identity to existing account. + log.info "LDAP account found for user #{user.username}. Building new #{auth_hash.provider} identity." user.identities.build(extern_uid: auth_hash.uid, provider: auth_hash.provider) else - # No account in Gitlab yet: create it and add the LDAP identity - user = build_new_user + log.info "No existing LDAP account was found in GitLab. Checking for #{auth_hash.provider} account." + user = find_by_uid_and_provider + if user.nil? + log.info "No user found using #{auth_hash.provider} provider. Creating a new one." + user = build_new_user + end + log.info "Correct account has been found. Adding LDAP identity to user: #{user.username}." user.identities.new(provider: ldap_person.provider, extern_uid: ldap_person.dn) end diff --git a/lib/gitlab/saml/user.rb b/lib/gitlab/saml/user.rb index dba4bbfc899..8943022612c 100644 --- a/lib/gitlab/saml/user.rb +++ b/lib/gitlab/saml/user.rb @@ -12,12 +12,12 @@ module Gitlab end def gl_user - @user ||= find_by_uid_and_provider - if auto_link_ldap_user? @user ||= find_or_create_ldap_user end + @user ||= find_by_uid_and_provider + if auto_link_saml_user? @user ||= find_by_email end diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb index 7f6ef71b303..56af739b1ef 100644 --- a/lib/gitlab/workhorse.rb +++ b/lib/gitlab/workhorse.rb @@ -6,6 +6,13 @@ module Gitlab SEND_DATA_HEADER = 'Gitlab-Workhorse-Send-Data' class << self + def git_http_ok(repository, user) + { + 'GL_ID' => Gitlab::ShellEnv.gl_id(user), + 'RepoPath' => repository.path_to_repo, + } + end + def send_git_blob(repository, blob) params = { 'RepoPath' => repository.path_to_repo, diff --git a/lib/tasks/gitlab/db.rake b/lib/tasks/gitlab/db.rake index 86584e91093..7230b9485be 100644 --- a/lib/tasks/gitlab/db.rake +++ b/lib/tasks/gitlab/db.rake @@ -34,7 +34,7 @@ namespace :gitlab do # PG: http://www.postgresql.org/docs/current/static/ddl-depend.html # MySQL: http://dev.mysql.com/doc/refman/5.7/en/drop-table.html # Add `IF EXISTS` because cascade could have already deleted a table. - tables.each { |t| connection.execute("DROP TABLE IF EXISTS #{t} CASCADE") } + tables.each { |t| connection.execute("DROP TABLE IF EXISTS #{connection.quote_table_name(t)} CASCADE") } end desc 'Configures the database by running migrate, or by loading the schema and seeding if needed' |