Skip to content

Implement login with private registry#1564

Merged
vieux merged 7 commits intomoby:masterfrom
mhennings:1357-implement-login-with-private-registry
Sep 9, 2013
Merged

Implement login with private registry#1564
vieux merged 7 commits intomoby:masterfrom
mhennings:1357-implement-login-with-private-registry

Conversation

@mhennings
Copy link
Contributor

To improve the use of docker with a private registry the login
command is extended with a parameter for the server address.

While implementing i noticed that two problems hindered authentication to a
private registry:

  1. the resolve of the authentication did not match during push
    because the looked up key was for example localhost:8080 but
    the stored one would have been https://localhost:8080

    Besides The lookup needs to still work if the https->http fallback
    is used

  2. During pull of an image no authentication is sent, which
    means all repositories are expected to be private.

These points are fixed now. The changes are implemented in
a way to be compatible to existing behavior both in the
API as also with the private registry.

Update:

  • login does not require the full url any more, you can login
    to the repository prefix:

    example:
    docker logon localhost:8080

Fixed corner corner cases:

  • When login is done during pull and push the registry endpoint is used and
    not the central index
  • When Remote sends a 401 during pull, it is now correctly delegating to
    CmdLogin
  • After a Login is done pull and push are using the newly entered login data,
    and not the previous ones. This one seems to be also broken in master, too.
  • Auth config is now transfered in a parameter instead of the body when
    /images/create is called.

@mhennings
Copy link
Contributor Author

this fixes #1357

@mhennings
Copy link
Contributor Author

@samalba please have a look

@samalba
Copy link
Contributor

samalba commented Aug 16, 2013

Thanks Marco for the contribution, it looks really good. I'll have a closer look today, especially to test it.

cc @shin-

@avaerkazmer
Copy link

Played around with this one at some length; looks like there's still a couple of warts:

  1. login command doesn't hit the right url if you do the obvious thing like docker login 127.0.0.1:8080. It will complain to varying degrees until you login with the crazy format docker login http://127.0.0.1:8080/v1/. It shouldn't be that nasty.
  2. If you're not logged in (in conf) when hitting a private registry for the first time (and it replies 401), the login will just prompt to login to the main index (and this isn't even obvious).

Basically, could use a bit more polishing + test cases.

But with the right incantations it seems to work.

@mhennings
Copy link
Contributor Author

@avaer Thank you for pointing out theese corner cases. I've updated the commit to cover theses issues.

@avaerkazmer
Copy link

Cool, seems to be working as advertised now. Eagerly waiting for this in mainline :).

@shin-
Copy link
Contributor

shin- commented Aug 19, 2013

Looks good, I think it would also be useful to support this:

# docker login http://localhost:5000
2013/08/19 16:53:07 Invalid Registry endpoint: Get http://localhost:5000_ping: unknown port tcp/5000_ping

@mhennings
Copy link
Contributor Author

@shin-

While i think that its better to support only well defined formats, I see that a user might run into that case.
So if a user comes now with a url without a path, it is now expanded to /v1/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this magic number 9?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to test if the url has a path it is significant if it has a / after 'http://' or 'https://' which is the 8th char.

I personally think that doing tricks to urls is mostly wrong. So the implementation was originally only handling the two most significant cases:

  • Full URL
  • Prefix format

Though shin- has a point, that users might just do that and wonder.

@mhennings
Copy link
Contributor Author

I updated the commit to rebase and fix a bug with the way I transfer the authConfig to the docker api.

@mhennings
Copy link
Contributor Author

@shin- @samalba
i would appreciate if you could have another look at this.

@shin-
Copy link
Contributor

shin- commented Aug 22, 2013

Hey,

I think you're misisng an import in api.go :(

# go build
# github.com/dotcloud/docker
../../src/github.com/dotcloud/docker/api.go:400: undefined: base64

@mhennings
Copy link
Contributor Author

@shin- thanks, made an error during rebase/merge. its fixed now.

@shin-
Copy link
Contributor

shin- commented Aug 22, 2013

Alright, LGTM 👍

@vieux
Copy link
Contributor

vieux commented Aug 22, 2013

@mhennings any particular reason to pass the authConfig via parameter in postImagesCreate ?
It's not consistent with postImagesPush

Maybe we could add parameter support in postImagesPush (but keep body undocumented to maintain compatibility)

@mhennings
Copy link
Contributor Author

@vieux it had to be passed as a parameter because the same api endpoint is used for

docker import - < xyz.tar

If you like to move the authConfig on postImagePush into a parameter I can do that.

@mhennings
Copy link
Contributor Author

@vieux Ok, ive moved the parameter

I've also rebased and made sure LoadConfig is called, as that PR went in in the meantime

@mhennings
Copy link
Contributor Author

The last change you see here does two things:

  • a rebase to current master
  • when a image is pulled during the run cmd the correct auth is sent to the server.

To make it easer to keep track of these small additons i've started to put commits on top

api.go Outdated
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you base64 encoding entire JSON object? Why would you not pass authentication data via the Authentication header?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure having the authConfig data in an Authentication header is the best idea -- the header implies that you're authenticating to the API itself. Here, we're passing auth data that will be used by the API further down the line to perform certain operations, so I like the idea of having it as a parameter better.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shin- Is there a good reason to base64 the entire json obj?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Encoding the full object is the way it was done before and i do not see a reason to change that.
The only difference is that it is now a parameter because it would conflict as the body.

if i replace that with a pseudo basic auth i would create new problems

  • not all relevant parameters are transfered (server address is needed)
  • future changes to enable stronger auth would be restricted without need
  • the code becomes incompatible to current api
  • users could expect full basic auth behaviour which is not intended at these routes

encoding as base64 is required to be url safe

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mhennings I don't get why you say Encoding the full object is the way it was done before,
you added "encoding/base64" yourself, before it was simply sent has body.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vieux

It was not encoded as base64 but sent as a full json object in the body of the request of the "push" part.
There was no authentication during pull.

I understood the question to be regarding sending a full object instead of a basic auth header.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the base64 is fine AFAIC. URL-encoding a JSON dict would get ugly really fast.

@mhennings
Copy link
Contributor Author

@crosbymichael @shin- @vieux

If there are questions open i would be happy if we could resolve them.

If not -- maybe we could merge this?

Kind regards,

Marco

@kyleconroy
Copy link
Contributor

I'm a bit confused on why you need the "server address" field in the authConfig. Isn't this redundant information? ~/.dockercfg already stores the server address as the key to authConfig object.

@mhennings
Copy link
Contributor Author

@kyleconroy
The ~/.dockerconfig contains the Server Address in the section. And this remains unchanged. But when doing a login request to the docker deamon the client process needs to submit the server to login to to the docker daemon.

This is because the ~/.dockerconfig file is read by the client process and not the docker daemon.

When doing a pull or push the server address is taken from the repository prefix (so this also remains as it is now).

Hope this helps understanding the changes.

@mhennings
Copy link
Contributor Author

The http header changes of @shin- are merged, and the changeset was rebased. (the history is long, because i did a full cherry-pick to ease the rebase)

@vieux
Copy link
Contributor

vieux commented Aug 30, 2013

@shin- I think you should keep support for body in postImagesPush (and maybe remove it in the next version 1.5) or update this PR to version API 1.5.

It's a big change, it break compat.

@shin-
Copy link
Contributor

shin- commented Aug 30, 2013

Yep, I was thinking about that. Let's bump the API version to 1.5 and include this change + #1701

@vieux
Copy link
Contributor

vieux commented Aug 30, 2013

Great

@crosbymichael
Copy link
Contributor

@mhennings Can you please rebase your changes?

To improve the use of docker with a private registry the login
command is extended with a parameter for the server address.

While implementing i noticed that two problems hindered authentication to a
private registry:

1. the resolve of the authentication did not match during push
   because the looked up key was for example localhost:8080 but
   the stored one would have been https://localhost:8080

   Besides The lookup needs to still work if the https->http fallback
   is used

2. During pull of an image no authentication is sent, which
   means all repositories are expected to be private.

These points are fixed now. The changes are implemented in
a way to be compatible to existing behavior both in the
API as also with the private registry.

Update:

- login does not require the full url any more, you can login
  to the repository prefix:

  example:
  docker logon localhost:8080

Fixed corner corner cases:

- When login is done during pull and push the registry endpoint is used and
  not the central index

- When Remote sends a 401 during pull, it is now correctly delegating to
  CmdLogin

- After a Login is done pull and push are using the newly entered login data,
  and not the previous ones. This one seems to be also broken in master, too.

- Auth config is now transfered in a parameter instead of the body when
  /images/create is called.
@mhennings
Copy link
Contributor Author

@crosbymichael

Done. There where some minor merges. I have tested that it still works.

@aslakhellesoy
Copy link

@mhennings does this change mean I can run my own docker-registry and force people to authenticate for both pull and push? (I want people to authenticate when pulling images from my registry).

@mhennings
Copy link
Contributor Author

@aslakhellesoy
Yes, pull and push can use authentication.

Please note that you need to setup basic auth on the server side, too.
(for example by using a proxy)

@lukewpatterson
Copy link

@mhennings, you said to _aslakhellesoy - "Yes, pull and push can use authentication. ... you need to setup basic auth on the server side, too."

Have you successfully authenticated and pushed/pulled using basic auth? Your changes only enabled a custom index for auth, right? I'm asking because I've tried and tried using basic auth, with no luck. Please see also docker-archive/docker-registry#82 (comment)

Does anyone have a full example of how to use basic auth with a private registry? That'd be awesome.

@mhennings
Copy link
Contributor Author

@lukewpatterson in theory it can be done by a proxy the handles basic auth.
but some parts of the code expect a auth token to be supplied by the /auth call.

after thinking about it it seems more realistic to implement it inside the open sourced registry.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants