BigW Consortium Gitlab

openid_connect_spec.rb 4.84 KB
Newer Older
1 2 3
require 'spec_helper'

describe 'OpenID Connect requests' do
4
  let(:user) { create :user }
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
  let(:access_grant) { create :oauth_access_grant, application: application, resource_owner_id: user.id }
  let(:access_token) { create :oauth_access_token, application: application, resource_owner_id: user.id }

  def request_access_token
    login_as user

    post '/oauth/token',
      grant_type: 'authorization_code',
      code: access_grant.token,
      redirect_uri: application.redirect_uri,
      client_id: application.uid,
      client_secret: application.secret
  end

  def request_user_info
    get '/oauth/userinfo', nil, 'Authorization' => "Bearer #{access_token.token}"
  end

  def hashed_subject
    Digest::SHA256.hexdigest("#{user.id}-#{Rails.application.secrets.secret_key_base}")
  end

  context 'Application without OpenID scope' do
    let(:application) { create :oauth_application, scopes: 'api' }

    it 'token response does not include an ID token' do
      request_access_token

      expect(json_response).to include 'access_token'
      expect(json_response).not_to include 'id_token'
    end

    it 'userinfo response is unauthorized' do
      request_user_info

40
      expect(response).to have_gitlab_http_status 403
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
      expect(response.body).to be_blank
    end
  end

  context 'Application with OpenID scope' do
    let(:application) { create :oauth_application, scopes: 'openid' }

    it 'token response includes an ID token' do
      request_access_token

      expect(json_response).to include 'id_token'
    end

    context 'UserInfo payload' do
      let(:user) do
        create(
          :user,
          name: 'Alice',
          username: 'alice',
          emails: [private_email, public_email],
          email: private_email.email,
          public_email: public_email.email,
          website_url: 'https://example.com',
64
          avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png")
65 66 67
        )
      end

68 69
      let!(:public_email) { build :email, email: 'public@example.com' }
      let!(:private_email) { build :email, email: 'private@example.com' }
70

71 72 73 74
      let!(:group1) { create :group }
      let!(:group2) { create :group }
      let!(:group3) { create :group, parent: group2 }
      let!(:group4) { create :group, parent: group3 }
75 76 77 78 79 80 81

      before do
        group1.add_user(user, GroupMember::OWNER)
        group3.add_user(user, Gitlab::Access::DEVELOPER)
      end

      it 'includes all user information and group memberships' do
82 83
        request_user_info

84
        expect(json_response).to match(a_hash_including({
85 86 87 88 89 90 91
          'sub'            => hashed_subject,
          'name'           => 'Alice',
          'nickname'       => 'alice',
          'email'          => 'public@example.com',
          'email_verified' => true,
          'website'        => 'https://example.com',
          'profile'        => 'http://localhost/alice',
92
          'picture'        => "http://localhost/uploads/-/system/user/avatar/#{user.id}/dk.png",
93 94 95
          'groups'         => anything
        }))

96 97
        expected_groups = [group1.full_path, group3.full_path]
        expected_groups << group4.full_path if Group.supports_nested_groups?
98
        expect(json_response['groups']).to match_array(expected_groups)
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
      end
    end

    context 'ID token payload' do
      before do
        request_access_token
        @payload = JSON::JWT.decode(json_response['id_token'], :skip_verification)
      end

      it 'includes the Gitlab root URL' do
        expect(@payload['iss']).to eq Gitlab.config.gitlab.url
      end

      it 'includes the hashed user ID' do
        expect(@payload['sub']).to eq hashed_subject
      end

116
      it 'includes the time of the last authentication', :clean_gitlab_redis_shared_state do
117 118 119 120 121 122 123 124
        expect(@payload['auth_time']).to eq user.current_sign_in_at.to_i
      end

      it 'does not include any unknown properties' do
        expect(@payload.keys).to eq %w[iss sub aud exp iat auth_time]
      end
    end

125 126 127 128 129 130 131 132 133
    # These 2 calls shouldn't actually throw, they should be handled as an
    # unauthorized request, so we should be able to check the response.
    #
    # This was not possible due to an issue with Warden:
    # https://github.com/hassox/warden/pull/162
    #
    # When the patch gets merged and we update Warden, these specs will need to
    # updated to check the response instead of a raised exception.
    # https://gitlab.com/gitlab-org/gitlab-ce/issues/40218
134 135 136 137 138 139 140
    context 'when user is blocked' do
      it 'returns authentication error' do
        access_grant
        user.block

        expect do
          request_access_token
141
        end.to raise_error UncaughtThrowError
142 143 144 145 146 147 148 149 150 151
      end
    end

    context 'when user is ldap_blocked' do
      it 'returns authentication error' do
        access_grant
        user.ldap_block

        expect do
          request_access_token
152
        end.to raise_error UncaughtThrowError
153 154 155 156
      end
    end
  end
end