-
Notifications
You must be signed in to change notification settings - Fork 76
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[JENKINS-48437] Authorization for Docker Endpoint #68
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not entirely sure what is going on here but this does not look like the right solution to me. Anyway there is no downstream PR in docker-workflow
using a timestamped snapshot to consume the newly introduced APIs, much less a test that demonstrates the bug and the effectiveness of the fix using MockQueueItemAuthenticator
.
@@ -182,10 +185,35 @@ DockerRegistryToken getToken(Item context) { | |||
|
|||
// look for subtypes that know how to create a token, such as Google Container Registry | |||
return AuthenticationTokens.convert(DockerRegistryToken.class, firstOrNull(CredentialsProvider.lookupCredentials( | |||
IdCredentials.class, context, Jenkins.getAuthentication(),requirements), | |||
IdCredentials.class, context, Tasks.getAuthenticationOf((Queue.Task)context),requirements), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Smells wrong. As you can see from the Javadoc of that method, it is a prediction, not an indication of what actual authentication is associated with the build—which would be Jenkins.getAuthentication()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an attempt to fix the JENKINS-48437 without needing to update the dependencies in docker-worflow
(or other dependents of docker-commons
).
domainRequirements); | ||
} | ||
|
||
// the directory needs to be outside workspace to avoid prying eyes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a new overload is indeed necessary, clearly we would want the duplicated code to be factored out into an internal method somehow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jglick How do you want me to factor this out exactly ? I don't see how I could avoid to duplicate the code here unless I use a typing like Object
or one of the interface that Run
and Item
have in common (not sure if doing this would make sense though). So is it worth it ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it does not matter so long as only one nondeprecated code path remains.
@jglick Are the PR builds deploying snapshots that I can use ? How exactly can I do the following ?:
|
No; traditionally this was done by a manual |
…#70 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jglick Could I get further review ?
domainRequirements); | ||
} | ||
|
||
// the directory needs to be outside workspace to avoid prying eyes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jglick How do you want me to factor this out exactly ? I don't see how I could avoid to duplicate the code here unless I use a typing like Object
or one of the interface that Run
and Item
have in common (not sure if doing this would make sense though). So is it worth it ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Credentials stuff looks correct from 10,000ft
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few nits. Will have to take @stephenc’s word for it on the appropriateness of the new API calls, since there is no functional test. (I never managed to write one in DockerRegistryEndpointTest
, especially now as it would be trying to run docker login
, so you would need to either have a mock endpoint accepting the authentication or wrap in a test block step with a LauncherDecorator
that just echoes commands rather than actually running them.)
src/main/java/org/jenkinsci/plugins/docker/commons/credentials/DockerRegistryEndpoint.java
Show resolved
Hide resolved
domainRequirements); | ||
} | ||
|
||
// the directory needs to be outside workspace to avoid prying eyes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it does not matter so long as only one nondeprecated code path remains.
* specify that build. Otherwise null. If you are scoped to something else, you might | ||
* have to interact with {@link CredentialsProvider} directly. | ||
*/ | ||
public @CheckForNull DockerRegistryToken getToken(Run context) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this public
if it is only called internally and from tests? Make it default access. If and when some other plugin actually needs to call this (apparently docker-workflow
does not), a separate set of PRs can be made which demonstrates the usage.
* | ||
* @param context | ||
* If you are a build step trying to access DockerHub in the context of a build/job, | ||
* specify that build. Otherwise null. If you are scoped to something else, you might |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Otherwise null.
Then mark it @CheckForNull
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in bc6d2de.
@@ -181,12 +190,44 @@ DockerRegistryToken getToken(Item context) { | |||
// shrug off this error and move on. We are matching with ID anyway. | |||
} | |||
|
|||
Authentication runAuth = context instanceof Queue.Task ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why it getToken(Item)
being patched if this method no longer being used?
src/test/java/org/jenkinsci/plugins/docker/commons/credentials/DockerRegistryEndpointTest.java
Show resolved
Hide resolved
@@ -72,6 +89,56 @@ public void testParseNullUrlAndImageName() throws Exception { | |||
new DockerRegistryEndpoint(null, null).imageName(null); | |||
} | |||
|
|||
@Issue("JENKINS-48437") | |||
@Test | |||
public void testGetTokenForItem() throws IOException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we care about this case? IIUC it is deprecated anyway.
globalCredentialsId, "test-global-creds", "user", "password"); | ||
CredentialsProvider.lookupStores(j.jenkins).iterator().next().addCredentials(Domain.global(), credentials); | ||
|
||
FreeStyleProject item = j.createFreeStyleProject("testGetToken"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW @Rule JenkinsRule
starts a new instance for each test case, so there is no need to pass a job name argument.
|
||
FreeStyleProject item = j.createFreeStyleProject("testGetToken"); | ||
|
||
SecurityContextHolder.getContext().setAuthentication(User.get("alice").impersonate()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rather use ACL.as
, even in tests. Just safer.
import hudson.model.*; | ||
import jenkins.model.Jenkins; | ||
import org.acegisecurity.context.SecurityContextHolder; | ||
import org.apache.commons.codec.binary.Base64; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW there is a standard utility now in Java 8.
…though you could write a downstream functional test demonstrating the complete scenario in |
@jglick any plans to accept this PR or fix this bug by Jenkins core team? |
Adding tests downstream: jenkinsci/docker-workflow-plugin#141 |
Jenkins core team has nothing to do with this plugin. Individual
contributors might be interested, but AFAIK there is no active maintainer
here
…On Tue, Mar 5, 2019, 01:27 Allan Burdajewicz ***@***.***> wrote:
Adding tests downstream: jenkinsci/docker-workflow-plugin#141
<jenkinsci/docker-workflow-plugin#141>
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#68 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AC3IoIvwGk9e5o7sQwTZyslL5D6KHF7uks5vTboKgaJpZM4S92l7>
.
|
Hoping to get an update on releasing this? It's currently blocking me from using docker within pipelines with authentication. Thanks in advance! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I dug through the credential-related APIs to understand the key differences between the old and new code. The summary is that CredentialsProvider.findCredentialById
has a fallback to call Credentials.lookupCredentials
with ACL.SYSTEM
if the Run
's authentication has Credentials.USE_ITEM
permissions (implied by Job.CONFIGURE
in practice) on the Run
's Job. Users without Credentials.USE_ITEM
still won't be able to use credentials in some cases if authorize-project is in use, so that's something to keep in mind if we see further reports from users.
We could inline that same fallback here to avoid introducing new APIs and deprecating the existing ones, but Credentials.findCredentialById
has other fallbacks related to parameters that might matter in some cases so I think this PR is the best approach.
I submitted #74 which subsumes this PR to address the minor nits I noted and to add another case to the new test to make the permissions that matter a bit clearer.
* | ||
* @param context | ||
* If you are a build step trying to access DockerHub in the context of a build/job, | ||
* specify that build. Otherwise null. If you are scoped to something else, you might |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in bc6d2de.
import hudson.model.Describable; | ||
import hudson.model.Descriptor; | ||
import hudson.model.Item; | ||
import hudson.model.*; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: please don't do this in non-test code (and even in test code I tend to avoid it for things other than assertion methods or similar)
try { | ||
requirements = Collections.<DomainRequirement>singletonList(new HostnameRequirement(getEffectiveUrl().getHost())); | ||
} catch (IOException e) { | ||
LOGGER.log(Level.WARNING, "Could not initiliaze registry URL: ", e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: typo. Also, given that the previous code didn't log here, would it be best for this to not log as well, or at least to log only at Level.FINE
(and make the old code log as well for consistency)?
JENKINS-48437
Proposed a fix for the issue with the method that retrieves the credentials to get the DockerRegistryToken.
Add implementation accepting a
Run
as context (and using CredentialsProvider.findCredentialById) that can be later leverage by docker-workflow.@reviewbybees