Skip to content
This repository has been archived by the owner on Apr 17, 2023. It is now read-only.

Commit

Permalink
Merge pull request #282 from SUSE/issue-276
Browse files Browse the repository at this point in the history
Support auth protocol introduced by docker 1.8
  • Loading branch information
flavio committed Sep 2, 2015
2 parents 2d4e89e + b717fb9 commit ea4751e
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ PR [#212](https://github.com/SUSE/Portus/pull/212).
- Added the appliance tests. See PR [#208](https://github.com/SUSE/Portus/pull/208).
- Star/Unstar repositories. See PR [#230](https://github.com/SUSE/Portus/pull/230).
- Now users can be disabled. See PR [#240](https://github.com/SUSE/Portus/pull/240).
- Fixed the authentication process for Docker 1.8. See PR
[#282](https://github.com/SUSE/Portus/pull/282).
- And some minor fixes here and there.

## 1.0.1
Expand Down
20 changes: 19 additions & 1 deletion app/controllers/api/v2/tokens_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,36 @@ def show
def authorize_scopes(registry)
return unless params[:scope]

# First try to fetch the requested scopes and the handler. If no scopes
# were successfully given, respond with a 401.
auth_scope, scopes = scope_handler(registry, params[:scope])
raise Pundit::NotAuthorizedError, "No scopes to handle" if scopes.empty?

scopes.each do |scope|
# It will try to check if the current user is authorized to access the
# scope given in this iteration. If everything is fine, then nothing will
# happen, otherwise there are two possible exceptions that can be raised:
#
# - NoMethodError: the targeted resource does not handle the scope that
# is being checked. It will raise a ScopeNotHandled.
# - Pundit::NotAuthorizedError: the targeted resource unauthorized the
# given user for the scope that is being checked. In this case this
# scope gets removed from `auth_scope.actions`.
begin
authorize auth_scope.resource, "#{scope}?".to_sym
rescue NoMethodError
logger.warn "Cannot handle scope #{scope}"
raise ScopeNotHandled, "Cannot handle scope #{scope}"
rescue Pundit::NotAuthorizedError
logger.debug "scope #{scope} not authorized, removing from actions"
auth_scope.actions.delete_if { |a| a == scope }
end
end

# If auth_scope.actions is empty, it means that the previous loop
# unauthorized all the requested scopes for the current user. Therefore
# respond with a 401. Otherwise, return the resulting auth_scope.
raise Pundit::NotAuthorizedError if auth_scope.actions.empty?
auth_scope
end

Expand All @@ -61,6 +79,6 @@ def scope_handler(registry, scope_string)
raise ScopeNotHandled
end

[auth_scope, auth_scope.scopes]
[auth_scope, auth_scope.scopes.dup]
end
end
40 changes: 39 additions & 1 deletion spec/api/v2/token_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,26 @@
end
end

context "as another user" do
let(:another) { create(:user, password: password) }

it "does not allow to pull a private namespace from another team" do
# It works for the regular user
get v2_token_url,
{ service: registry.hostname, account: user.username, scope: "repository:#{user.username}/busybox:push,pull" },
"HTTP_AUTHORIZATION" => auth_mech.encode_credentials(user.username, password)

expect(response.status).to eq 200

# But not for another
get v2_token_url,
{ service: registry.hostname, account: another.username, scope: "repository:#{user.username}/busybox:push,pull" },
"HTTP_AUTHORIZATION" => auth_mech.encode_credentials(another.username, password)

expect(response.status).to eq 401
end
end

context "as valid user" do
let(:valid_request) do
{
Expand Down Expand Up @@ -119,7 +139,7 @@
end
end

context "reposity scope" do
context "repository scope" do
it "delegates authentication to the Namespace policy" do
personal_namespace = Namespace.find_by(name: user.username)
expect_any_instance_of(Api::V2::TokensController).to receive(:authorize)
Expand All @@ -135,6 +155,24 @@
},
valid_auth_header
end

it "allows to pull an image in which this user is just a viewer" do
# Quick way to force a "viewer" policy.
allow_any_instance_of(NamespacePolicy).to receive(:push?).and_return(false)
allow_any_instance_of(NamespacePolicy).to receive(:pull?).and_return(true)

get v2_token_url,
{ service: registry.hostname, account: user.username, scope: "repository:#{user.username}/busybox:push,pull" },
valid_auth_header

expect(response.status).to eq 200

# And check that the only authorized scope is "pull"
token = JSON.parse(response.body)["token"]
payload = JWT.decode(token, nil, false, leeway: 2)[0]
expect(payload["access"][0]["name"]).to eq "#{user.username}/busybox"
expect(payload["access"][0]["actions"]).to match_array ["pull"]
end
end

context "registry scope" do
Expand Down

0 comments on commit ea4751e

Please sign in to comment.