diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/api/internal.rb | 13 | ||||
-rw-r--r-- | lib/gitlab/git_access.rb | 43 | ||||
-rw-r--r-- | lib/gitlab/git_access_wiki.rb | 7 | ||||
-rw-r--r-- | lib/gitlab/ldap/user.rb | 75 | ||||
-rw-r--r-- | lib/gitlab/markdown.rb | 18 | ||||
-rw-r--r-- | lib/gitlab/oauth/auth_hash.rb | 2 | ||||
-rw-r--r-- | lib/gitlab/oauth/user.rb | 71 | ||||
-rw-r--r-- | lib/redcarpet/render/gitlab_html.rb | 12 | ||||
-rw-r--r-- | lib/support/nginx/gitlab-ssl | 9 | ||||
-rw-r--r-- | lib/tasks/gitlab/import.rake | 5 |
10 files changed, 153 insertions, 102 deletions
diff --git a/lib/api/internal.rb b/lib/api/internal.rb index 5f484f63418..9ac659f50fd 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -14,13 +14,20 @@ module API # post "/allowed" do status 200 + project_path = params[:project] # Check for *.wiki repositories. # Strip out the .wiki from the pathname before finding the # project. This applies the correct project permissions to # the wiki repository as well. - project_path = params[:project] - project_path.gsub!(/\.wiki/,'') if project_path =~ /\.wiki/ + access = + if project_path =~ /\.wiki\Z/ + project_path.sub!(/\.wiki\Z/, '') + Gitlab::GitAccessWiki.new + else + Gitlab::GitAccess.new + end + project = Project.find_with_namespace(project_path) return false unless project @@ -32,7 +39,7 @@ module API return false unless actor - Gitlab::GitAccess.new.allowed?( + access.allowed?( actor, params[:action], project, diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb index 6247dd59867..b768a99a0e8 100644 --- a/lib/gitlab/git_access.rb +++ b/lib/gitlab/git_access.rb @@ -49,25 +49,7 @@ module Gitlab # Iterate over all changes to find if user allowed all of them to be applied changes.each do |change| - oldrev, newrev, ref = change.split(' ') - - action = if project.protected_branch?(branch_name(ref)) - # we dont allow force push to protected branch - if forced_push?(project, oldrev, newrev) - :force_push_code_to_protected_branches - # and we dont allow remove of protected branch - elsif newrev =~ /0000000/ - :remove_protected_branches - else - :push_code_to_protected_branches - end - elsif project.repository && project.repository.tag_names.include?(tag_name(ref)) - # Prevent any changes to existing git tag unless user has permissions - :admin_project - else - :push_code - end - unless user.can?(action, project) + unless change_allowed?(user, project, change) # If user does not have access to make at least one change - cancel all push return false end @@ -77,6 +59,29 @@ module Gitlab true end + def change_allowed?(user, project, change) + oldrev, newrev, ref = change.split(' ') + + action = if project.protected_branch?(branch_name(ref)) + # we dont allow force push to protected branch + if forced_push?(project, oldrev, newrev) + :force_push_code_to_protected_branches + # and we dont allow remove of protected branch + elsif newrev =~ /0000000/ + :remove_protected_branches + else + :push_code_to_protected_branches + end + elsif project.repository && project.repository.tag_names.include?(tag_name(ref)) + # Prevent any changes to existing git tag unless user has permissions + :admin_project + else + :push_code + end + + user.can?(action, project) + end + def forced_push?(project, oldrev, newrev) return false if project.empty_repo? diff --git a/lib/gitlab/git_access_wiki.rb b/lib/gitlab/git_access_wiki.rb new file mode 100644 index 00000000000..9f0eb3be20f --- /dev/null +++ b/lib/gitlab/git_access_wiki.rb @@ -0,0 +1,7 @@ +module Gitlab + class GitAccessWiki < GitAccess + def change_allowed?(user, project, change) + user.can?(:write_wiki, project) + end + end +end diff --git a/lib/gitlab/ldap/user.rb b/lib/gitlab/ldap/user.rb index 25b5a702f9a..006ef170726 100644 --- a/lib/gitlab/ldap/user.rb +++ b/lib/gitlab/ldap/user.rb @@ -10,22 +10,6 @@ module Gitlab module LDAP class User < Gitlab::OAuth::User class << self - def find_or_create(auth_hash) - self.auth_hash = auth_hash - find(auth_hash) || find_and_connect_by_email(auth_hash) || create(auth_hash) - end - - def find_and_connect_by_email(auth_hash) - self.auth_hash = auth_hash - user = model.find_by(email: self.auth_hash.email) - - if user - user.update_attributes(extern_uid: auth_hash.uid, provider: auth_hash.provider) - Gitlab::AppLogger.info("(LDAP) Updating legacy LDAP user #{self.auth_hash.email} with extern_uid => #{auth_hash.uid}") - return user - end - end - def authenticate(login, password) # Check user against LDAP backend if user is not authenticated # Only check with valid login and password to prevent anonymous bind results @@ -44,10 +28,18 @@ module Gitlab @adapter ||= OmniAuth::LDAP::Adaptor.new(ldap_conf) end - protected + def user_filter(login) + filter = Net::LDAP::Filter.eq(adapter.uid, login) + # Apply LDAP user filter if present + if ldap_conf['user_filter'].present? + user_filter = Net::LDAP::Filter.construct(ldap_conf['user_filter']) + filter = Net::LDAP::Filter.join(filter, user_filter) + end + filter + end - def find_by_uid_and_provider - find_by_uid(auth_hash.uid) + def ldap_conf + Gitlab.config.ldap end def find_by_uid(uid) @@ -58,24 +50,39 @@ module Gitlab def provider 'ldap' end + end - def raise_error(message) - raise OmniAuth::Error, "(LDAP) " + message - end + def initialize(auth_hash) + super + update_user_attributes + end - def ldap_conf - Gitlab.config.ldap - end + # instance methods + def gl_user + @gl_user ||= find_by_uid_and_provider || find_by_email || build_new_user + end - def user_filter(login) - filter = Net::LDAP::Filter.eq(adapter.uid, login) - # Apply LDAP user filter if present - if ldap_conf['user_filter'].present? - user_filter = Net::LDAP::Filter.construct(ldap_conf['user_filter']) - filter = Net::LDAP::Filter.join(filter, user_filter) - end - filter - end + def find_by_uid_and_provider + # LDAP distinguished name is case-insensitive + model. + where(provider: auth_hash.provider). + where('lower(extern_uid) = ?', auth_hash.uid.downcase).last + end + + def find_by_email + model.find_by(email: auth_hash.email) + end + + def update_user_attributes + gl_user.attributes = { + extern_uid: auth_hash.uid, + provider: auth_hash.provider, + email: auth_hash.email + } + end + + def changed? + gl_user.changed? end def needs_blocking? diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index 17512a51658..ddcce7557a0 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -70,14 +70,22 @@ module Gitlab insert_piece($1) end - # Context passed to the markdoqwn pipeline + # Used markdown pipelines in GitLab: + # GitlabEmojiFilter - performs emoji replacement. + # + # see https://gitlab.com/gitlab-org/html-pipeline-gitlab for more filters + filters = [ + HTML::Pipeline::Gitlab::GitlabEmojiFilter + ] + markdown_context = { - asset_root: File.join(root_url, - Gitlab::Application.config.assets.prefix) + asset_root: Gitlab.config.gitlab.url, + asset_host: Gitlab::Application.config.asset_host } - result = HTML::Pipeline::Gitlab::MarkdownPipeline.call(text, - markdown_context) + markdown_pipeline = HTML::Pipeline::Gitlab.new(filters).pipeline + + result = markdown_pipeline.call(text, markdown_context) text = result[:output].to_html(save_with: 0) allowed_attributes = ActionView::Base.sanitized_allowed_attributes diff --git a/lib/gitlab/oauth/auth_hash.rb b/lib/gitlab/oauth/auth_hash.rb index 0198f61f427..ce52beec78e 100644 --- a/lib/gitlab/oauth/auth_hash.rb +++ b/lib/gitlab/oauth/auth_hash.rb @@ -21,7 +21,7 @@ module Gitlab end def name - (info.name || full_name).to_s.force_encoding('utf-8') + (info.try(:name) || full_name).to_s.force_encoding('utf-8') end def full_name diff --git a/lib/gitlab/oauth/user.rb b/lib/gitlab/oauth/user.rb index b768eda185f..699258baee4 100644 --- a/lib/gitlab/oauth/user.rb +++ b/lib/gitlab/oauth/user.rb @@ -6,55 +6,52 @@ module Gitlab module OAuth class User - class << self - attr_reader :auth_hash + attr_accessor :auth_hash, :gl_user - def find(auth_hash) - self.auth_hash = auth_hash - find_by_uid_and_provider - end - - def create(auth_hash) - user = new(auth_hash) - user.save_and_trigger_callbacks - end + def initialize(auth_hash) + self.auth_hash = auth_hash + end - def model - ::User - end + def persisted? + gl_user.persisted? + end - def auth_hash=(auth_hash) - @auth_hash = AuthHash.new(auth_hash) - end + def new? + !gl_user.persisted? + end - protected - def find_by_uid_and_provider - model.where(provider: auth_hash.provider, extern_uid: auth_hash.uid).last - end + def valid? + gl_user.valid? end - # Instance methods - attr_accessor :auth_hash, :user + def save + gl_user.save! + log.info "(OAuth) saving user #{auth_hash.email} from login with extern_uid => #{auth_hash.uid}" + gl_user.block if needs_blocking? - def initialize(auth_hash) - self.auth_hash = auth_hash - self.user = self.class.model.new(user_attributes) - user.skip_confirmation! + gl_user + rescue ActiveRecord::RecordInvalid => e + log.info "(OAuth) Error saving user: #{gl_user.errors.full_messages}" + return self, e.record.errors + end + + def gl_user + @user ||= find_by_uid_and_provider || build_new_user end + protected def auth_hash=(auth_hash) @auth_hash = AuthHash.new(auth_hash) end - def save_and_trigger_callbacks - user.save! - log.info "(OAuth) Creating user #{auth_hash.email} from login with extern_uid => #{auth_hash.uid}" - user.block if needs_blocking? + def find_by_uid_and_provider + model.where(provider: auth_hash.provider, extern_uid: auth_hash.uid).last + end - user - rescue ActiveRecord::RecordInvalid => e - log.info "(OAuth) Email #{e.record.errors[:email]}. Username #{e.record.errors[:username]}" - return nil, e.record.errors + def build_new_user + model.new(user_attributes).tap do |user| + user.skip_confirmation! + end end def user_attributes @@ -80,6 +77,10 @@ module Gitlab def needs_blocking? Gitlab.config.omniauth['block_auto_created_users'] end + + def model + ::User + end end end end diff --git a/lib/redcarpet/render/gitlab_html.rb b/lib/redcarpet/render/gitlab_html.rb index c3378d6a18f..54d740908d5 100644 --- a/lib/redcarpet/render/gitlab_html.rb +++ b/lib/redcarpet/render/gitlab_html.rb @@ -10,6 +10,17 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML super options end + # If project has issue number 39, apostrophe will be linked in + # regular text to the issue as Redcarpet will convert apostrophe to + # #39; + # We replace apostrophe with right single quote before Redcarpet + # does the processing and put the apostrophe back in postprocessing. + # This only influences regular text, code blocks are untouched. + def normal_text(text) + return text unless text.present? + text.gsub("'", "’") + end + def block_code(code, language) # New lines are placed to fix an rendering issue # with code wrapped inside <h1> tag for next case: @@ -44,6 +55,7 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML end def postprocess(full_document) + full_document.gsub!("’", "'") unless @template.instance_variable_get("@project_wiki") || @project.nil? full_document = h.create_relative_links(full_document) end diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl index 5f1afe6575c..d3fb467ef27 100644 --- a/lib/support/nginx/gitlab-ssl +++ b/lib/support/nginx/gitlab-ssl @@ -19,7 +19,7 @@ ## - installing an old version of Nginx with the chunkin module [2] compiled in, or ## - using a newer version of Nginx. ## -## At the time of writing we do not know if either of these theoretical solutions works. +## At the time of writing we do not know if either of these theoretical solutions works. ## As a workaround users can use Git over SSH to push large files. ## ## [0] https://git.kernel.org/cgit/git/git.git/tree/Documentation/technical/http-protocol.txt#n99 @@ -42,7 +42,7 @@ server { listen *:80 default_server; server_name YOUR_SERVER_FQDN; ## Replace this with something like gitlab.example.com server_tokens off; ## Don't show the nginx version number, a security best practice - + ## Redirects all traffic to the HTTPS host root /nowhere; ## root doesn't have to be a valid path since we are redirecting rewrite ^ https://$server_name$request_uri? permanent; @@ -65,14 +65,15 @@ server { ssl_certificate /etc/nginx/ssl/gitlab.crt; ssl_certificate_key /etc/nginx/ssl/gitlab.key; - ssl_ciphers 'AES256+EECDH:AES256+EDH'; + # GitLab needs backwards compatible ciphers to retain compatibility with Java IDEs + ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4'; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_session_cache builtin:1000 shared:SSL:10m; ssl_prefer_server_ciphers on; - ## [WARNING] The following header states that the browser should only communicate + ## [WARNING] The following header states that the browser should only communicate ## with your server over a secure connection for the next 24 months. add_header Strict-Transport-Security max-age=63072000; add_header X-Frame-Options SAMEORIGIN; diff --git a/lib/tasks/gitlab/import.rake b/lib/tasks/gitlab/import.rake index cbfa736c84c..b6ed874e11a 100644 --- a/lib/tasks/gitlab/import.rake +++ b/lib/tasks/gitlab/import.rake @@ -27,7 +27,10 @@ namespace :gitlab do group_name = nil if group_name == '.' # Skip if group or user - next if namespaces.include?(name) + if namespaces.include?(name) + puts "Skipping #{project.name} due to namespace conflict with group or user".yellow + next + end puts "Processing #{repo_path}".yellow |