Skip to content
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

Use credentials plugin for managing authentication credentials #103

Merged
merged 5 commits into from
Mar 29, 2023

Conversation

ccHanibal
Copy link
Contributor

@ccHanibal ccHanibal commented Mar 23, 2023

As discussed in #102 this PR makes the plugin use the credentials plugin for managing credentials to confluence sites.
Existing credentials are migrated automatically on jenkins launch.
Also it adds support for credentials in the form of an API token used with Bearer authentication.

  • Make sure you are opening from a topic/feature/bugfix branch (right side) and not your main branch!
  • Ensure that the pull request title represents the desired changelog entry
  • Please describe what you did
  • Link to relevant issues in GitHub or Jira
  • Link to relevant pull requests, esp. upstream and downstream changes
  • Ensure you have provided tests - that demonstrates feature works or fixes the issue

@ccHanibal
Copy link
Contributor Author

Hoping to get this merged @jetersen, although the build failed again (as with #102), so I can continue to work on the bearer authentication feature. Or should I open a PR that does both at the same time?

@jetersen
Copy link
Member

I'd suggest adding the token bearer authentication in the same PR to reduce rework.

*/
@DataBoundConstructor
public ConfluenceSite(URL url, final String username, final String password) {
LOGGER.log(Level.FINER, "ctor args: " + url + ", " + username + ", " + password);
public ConfluenceSite(URL url, final String credentialsId) {
Copy link
Member

Choose a reason for hiding this comment

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

This breaks binary compatibility.

I suggest you create a new constructor and remove @DataBoundConstructor from this one mark this one deprecated.

So create a new constructor marked with @DataBoundConstructor that takes no arguments and then create a @DataBoundSetter for url and credentialsId

See why here: https://www.jenkins.io/doc/developer/plugin-development/pipeline-integration/#constructor-vs-setters

    /**
     * 
     *
     * @deprecated use {@link #new()} instead.  
     */
    @Deprecated
    public ConfluenceSite(URL url, final String username, final String password) {
        if (!url.toExternalForm().endsWith("/")) {
            try {
                url = new URL(url.toExternalForm() + "/");
            } catch (MalformedURLException e) {
                throw new AssertionError(e); // impossible
            }
        }

        this.url = url;
        this.username = hudson.Util.fixEmptyAndTrim(username);
        this.password = Secret.fromString(password);
    }

    @DataBoundConstructor
    public ConfluenceSite() {
    }
    
    /* ... you have these further below already */
    
    @DataBoundSetter
    public void setUrl(@CheckForNull URL url) {
        this.url = Util.fixEmptyAndTrim(url);
    }
    
    @DataBoundSetter
    public void setUrl(@CheckForNull String credentialsId) {
        this.credentialsId = Util.fixEmptyAndTrim(credentialsId);
    }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Did most exactly that.

Comment on lines 149 to 172
@Deprecated
public String getUsername(){
return username;
}

@DataBoundSetter
public void setUsername(String username){
this.username = Util.fixEmptyAndTrim(username);
}

@Deprecated
public Secret getPassword(){
return password;
}

@DataBoundSetter
public void setPassword(Secret password) {
this.password = password;
}

public void setPassword(String password) {
this.password = Secret.fromString(password);
}

Copy link
Member

Choose a reason for hiding this comment

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

I don't think you should add these as they would be considered obsolete and will be hard to remove once added.

Also they definitely should not have @DataBoundSetter when transient.

Suggested change
@Deprecated
public String getUsername(){
return username;
}
@DataBoundSetter
public void setUsername(String username){
this.username = Util.fixEmptyAndTrim(username);
}
@Deprecated
public Secret getPassword(){
return password;
}
@DataBoundSetter
public void setPassword(Secret password) {
this.password = password;
}
public void setPassword(String password) {
this.password = Secret.fromString(password);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are right. I was under the impression those were needed for XML serialisation. But they are not.

URIRequirementBuilder.create().build()),
CredentialsMatchers.withId(credentialsId));
if (credentials != null) {
if (credentials instanceof UsernamePasswordCredentials) {
Copy link
Member

Choose a reason for hiding this comment

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

I think the correct type is StandardUsernamePasswordCredentials as it is the interface while UsernamePasswordCredentials is the implementation as far as I recall.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

They are both interfaces.

Copy link
Contributor Author

@ccHanibal ccHanibal Mar 23, 2023

Choose a reason for hiding this comment

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

Now using StandardUsernamePasswordCredentials anyway, to be consistent across all places where credentials are retrieved.

* Keep original constructor as depricated
* Use StandardUsernamePasswordCredentials
@ccHanibal
Copy link
Contributor Author

I addressed your suggestions. More to come tomorrow.

import hudson.util.Secret;
import org.kohsuke.stapler.DataBoundConstructor;

public final class ConfluenceApiTokenImpl extends BaseStandardCredentials implements ConfluenceApiToken {
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we need to implement our own credential implementation. I think we should just use StringCredentials 😓 Sorry I did not provide enough context.

Which you can get from depending on this plugin without a version since it is in the jenkins plugin BOM: https://plugins.jenkins.io/plain-credentials/ it is broadly installed.

https://github.com/search?q=plain-credentials+org%3Ajenkinsci&type=code

Copy link
Contributor Author

@ccHanibal ccHanibal Mar 27, 2023

Choose a reason for hiding this comment

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

Hm yeah thought about that.
I got my inspiration from the GitLab plugin which does both, implement its own type and support StringCredentials. And I thought "we don't need both", but apparently I chose the "wrong" one.
Should be easy to change.

Copy link
Member

Choose a reason for hiding this comment

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

For newer implementation I would stick to StringCredentials unless there was a different need for multiple different string typed credentials.

Copy link
Member

@jetersen jetersen left a comment

Choose a reason for hiding this comment

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

One minor issue is the star imports. Once we fix those, this is ready.

import com.atlassian.confluence.rest.client.RestClientFactory;
import com.atlassian.confluence.rest.client.authentication.AuthenticatedWebResourceProvider;
import com.cloudbees.plugins.credentials.*;
Copy link
Member

Choose a reason for hiding this comment

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

I would ask if you can undo the star imports.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

import hudson.model.Descriptor;
import hudson.model.Hudson;
import hudson.Util;
import hudson.model.*;
Copy link
Member

Choose a reason for hiding this comment

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

Ditto

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@jetersen
Copy link
Member

@ccHanibal
Copy link
Contributor Author

ccHanibal commented Mar 29, 2023

@jetersen Tested with my local build and with the v154 hpi. Also tested the automatic migration of username and password after upgrading. All looked good.

@jetersen jetersen merged commit 38792a2 into jenkinsci:master Mar 29, 2023
@ccHanibal
Copy link
Contributor Author

Oh damn it.
Just noticed that I did not delete the resource file for rendering the custom ConfluenceApiTokenImpl (which has been removed): credentials/ConfluenceApiTokenImpl/credentials.jelly
I think we can just leave it in, but can cause potential irritations in the future.

@ccHanibal ccHanibal deleted the feature/use-credentials-plugin branch March 29, 2023 10:26
ccHanibal added a commit to ccHanibal/confluence-publisher-plugin that referenced this pull request Mar 29, 2023
@ccHanibal ccHanibal mentioned this pull request Mar 29, 2023
6 tasks
jetersen pushed a commit that referenced this pull request Mar 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants