diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..12301490 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 00000000..0d0b1c99 --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1 @@ +_extends: .github diff --git a/.github/workflows/cd.yaml b/.github/workflows/cd.yaml new file mode 100644 index 00000000..ff6a66d5 --- /dev/null +++ b/.github/workflows/cd.yaml @@ -0,0 +1,58 @@ +# Note: additional setup is required, see https://github.com/jenkinsci/incrementals-tools#automatic-deployment + +name: cd +on: + workflow_dispatch: + check_run: + types: + - completed + +jobs: + validate: + runs-on: ubuntu-latest + outputs: + should_release: ${{ steps.verify-ci-status.outputs.result == 'success' && steps.interesting-categories.outputs.interesting == 'true' }} + steps: + - name: Verify CI status + uses: jenkins-infra/verify-ci-status-action@v1.2.0 + id: verify-ci-status + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + output_result: true + + - name: Release Drafter + uses: release-drafter/release-drafter@v5 + if: steps.verify-ci-status.outputs.result == 'success' + with: + name: next + tag: next + version: next + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Check interesting categories + uses: jenkins-infra/interesting-category-action@v1.0.0 + id: interesting-categories + if: steps.verify-ci-status.outputs.result == 'success' + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + release: + runs-on: ubuntu-latest + needs: [validate] + if: needs.validate.outputs.should_release == 'true' + steps: + - name: Check out + uses: actions/checkout@v2.3.4 + with: + fetch-depth: 0 + - name: Set up JDK 8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Release + uses: jenkins-infra/jenkins-maven-cd-action@v1.1.0 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} + MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }} diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 112bdd40..43d62816 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -1,7 +1,7 @@ - - io.jenkins.tools.incrementals - git-changelist-maven-extension - 1.0-beta-7 - - \ No newline at end of file + + io.jenkins.tools.incrementals + git-changelist-maven-extension + 1.2 + + diff --git a/.mvn/maven.config b/.mvn/maven.config index ac318abc..f7daf60d 100644 --- a/.mvn/maven.config +++ b/.mvn/maven.config @@ -1,2 +1,3 @@ -Pconsume-incrementals --Pmight-produce-incrementals \ No newline at end of file +-Pmight-produce-incrementals +-Dchangelist.format=%d.v%s diff --git a/CHANGELOG.md b/CHANGELOG-old.md similarity index 93% rename from CHANGELOG.md rename to CHANGELOG-old.md index be33865a..a959daa6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG-old.md @@ -1,5 +1,7 @@ # Changelog +See [GitHub releases](https://github.com/jenkinsci/azure-ad-plugin/releases) for all newer versions. + ## 1.2.3 (2021-02-20) * Document update diff --git a/checkstyle.xml b/checkstyle.xml index 37af10a6..2328ddc3 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -4,8 +4,8 @@ --> + "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN" + "https://checkstyle.org/dtds/configuration_1_3.dtd"> @@ -76,9 +80,6 @@ - - - @@ -136,11 +137,10 @@ - + - - + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 374dc943..6a13b308 100644 --- a/pom.xml +++ b/pom.xml @@ -5,11 +5,11 @@ org.jenkins-ci.plugins plugin - 4.15 + 4.17 azure-ad - ${revision}${changelist} + ${changelist} Azure AD Plugin A Jenkins authentication & authorization plugin for Azure Active Directory @@ -37,15 +37,15 @@ - scm:git:ssh://github.com/jenkinsci/azure-ad-plugin.git - scm:git:ssh://git@github.com/jenkinsci/azure-ad-plugin.git - https://github.com/jenkinsci/azure-ad-plugin + scm:git:ssh://github.com/${gitHubRepo}.git + scm:git:ssh://git@github.com/${gitHubRepo}.git + https://github.com/${gitHubRepo} ${scmTag} - 1.2.4 - -SNAPSHOT + 9999-SNAPSHOT + jenkinsci/azure-ad-plugin UTF-8 UTF-8 @@ -180,7 +180,7 @@ io.jenkins.tools.bom bom-2.263.x - 19 + 26 import pom @@ -203,7 +203,7 @@ com.google.errorprone error_prone_annotations - 2.3.4 + 2.4.0 org.ow2.asm @@ -289,7 +289,14 @@ org.apache.maven.plugins maven-checkstyle-plugin - 2.17 + 3.1.1 + + + com.puppycrawl.tools + checkstyle + 8.41.1 + + validate diff --git a/src/main/java/com/microsoft/jenkins/azuread/AzureAdGroup.java b/src/main/java/com/microsoft/jenkins/azuread/AzureAdGroup.java index daf28f5e..eecf8d5d 100644 --- a/src/main/java/com/microsoft/jenkins/azuread/AzureAdGroup.java +++ b/src/main/java/com/microsoft/jenkins/azuread/AzureAdGroup.java @@ -1,41 +1,41 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See LICENSE file in the project root for license information. - */ - -package com.microsoft.jenkins.azuread; - -import org.acegisecurity.GrantedAuthority; - -public class AzureAdGroup implements GrantedAuthority { - - private String objectId; - - private String groupName; - - public AzureAdGroup(String objectId, String groupName) { - this.objectId = objectId; - this.groupName = groupName; - } - - @Override - public String getAuthority() { - return groupName; - } - - public String getObjectId() { - return objectId; - } - - public String getGroupName() { - return groupName; - } - - @Override - public String toString() { - return "AzureAdGroup{" - + "objectId='" + objectId + '\'' - + ", groupName='" + groupName + '\'' - + '}'; - } -} +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See LICENSE file in the project root for license information. + */ + +package com.microsoft.jenkins.azuread; + +import org.acegisecurity.GrantedAuthority; + +public class AzureAdGroup implements GrantedAuthority { + + private String objectId; + + private String groupName; + + public AzureAdGroup(String objectId, String groupName) { + this.objectId = objectId; + this.groupName = groupName; + } + + @Override + public String getAuthority() { + return groupName; + } + + public String getObjectId() { + return objectId; + } + + public String getGroupName() { + return groupName; + } + + @Override + public String toString() { + return "AzureAdGroup{" + + "objectId='" + objectId + '\'' + + ", groupName='" + groupName + '\'' + + '}'; + } +} diff --git a/src/main/java/com/microsoft/jenkins/azuread/AzureAdMatrixAuthorizationStrategy.java b/src/main/java/com/microsoft/jenkins/azuread/AzureAdMatrixAuthorizationStrategy.java index 2cfa6920..615c118e 100644 --- a/src/main/java/com/microsoft/jenkins/azuread/AzureAdMatrixAuthorizationStrategy.java +++ b/src/main/java/com/microsoft/jenkins/azuread/AzureAdMatrixAuthorizationStrategy.java @@ -1,249 +1,249 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See LICENSE file in the project root for license information. - */ - -package com.microsoft.jenkins.azuread; - -import com.cloudbees.hudson.plugins.folder.AbstractFolder; -import com.microsoft.azure.PagedList; -import com.microsoft.azure.management.Azure; -import com.microsoft.azure.management.graphrbac.GraphErrorException; -import com.microsoft.azure.management.graphrbac.implementation.ADGroupInner; -import com.microsoft.azure.management.graphrbac.implementation.UserInner; -import hudson.Extension; -import hudson.init.InitMilestone; -import hudson.init.Initializer; -import hudson.model.AbstractItem; -import hudson.model.AutoCompletionCandidates; -import hudson.model.Descriptor; -import hudson.model.Item; -import hudson.model.ItemGroup; -import hudson.model.Job; -import hudson.security.ACL; -import hudson.security.AuthorizationStrategy; -import hudson.security.GlobalMatrixAuthorizationStrategy; -import hudson.security.Permission; -import hudson.security.SecurityRealm; -import hudson.security.SidACL; -import jenkins.model.Jenkins; -import org.acegisecurity.Authentication; -import org.apache.commons.lang.StringUtils; -import org.jenkinsci.plugins.matrixauth.AuthorizationContainer; -import org.kohsuke.accmod.Restricted; -import org.kohsuke.accmod.restrictions.DoNotUse; -import org.kohsuke.accmod.restrictions.NoExternalUse; -import org.kohsuke.accmod.restrictions.suppressions.SuppressRestrictedWarnings; -import org.kohsuke.stapler.QueryParameter; - -import javax.annotation.Nonnull; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; -import java.util.logging.Logger; - -public class AzureAdMatrixAuthorizationStrategy extends GlobalMatrixAuthorizationStrategy { - - private static final Logger LOGGER = Logger.getLogger(AzureAdMatrixAuthorizationStrategy.class.getName()); - - private final transient ObjId2FullSidMap objId2FullSidMap = new ObjId2FullSidMap(); - - // - // Inheriting from ProjectMatrixAuthorizationStrategy will lead to conflict - // of AzureAdAuthorizationMatrixProperty and AuthorizationMatrixProperty. - // Copy codes instead. - // - @Override - @Nonnull - public ACL getACL(@Nonnull Job project) { - AzureAdAuthorizationMatrixProperty amp = project.getProperty(AzureAdAuthorizationMatrixProperty.class); - if (amp != null) { - return amp.getInheritanceStrategy().getEffectiveACL(amp.getACL(), project); - } else { - return getACL(project.getParent()); - } - } - - @Restricted(NoExternalUse.class) - public static ACL inheritingACL(final ACL parent, final ACL child) { - if (parent instanceof SidACL && child instanceof SidACL) { - return ((SidACL) child).newInheritingACL((SidACL) parent); - } - return new ACL() { - @Override - public boolean hasPermission(@Nonnull Authentication a, @Nonnull Permission permission) { - return a.equals(SYSTEM) || child.hasPermission(a, permission) || parent.hasPermission(a, permission); - } - }; - } - - public ACL getACL(ItemGroup g) { - if (g instanceof Item) { - Item item = (Item) g; - return item.getACL(); - } - return getRootACL(); - } - - @Override - @Nonnull - public ACL getACL(@Nonnull AbstractItem item) { - if (Jenkins.get().getPlugin("cloudbees-folder") != null) { // optional dependency - if (item instanceof AbstractFolder) { - AzureAdAuthorizationMatrixFolderProperty p = - ((AbstractFolder) item).getProperties().get(AzureAdAuthorizationMatrixFolderProperty.class); - if (p != null) { - return p.getInheritanceStrategy().getEffectiveACL(p.getACL(), item); - } - } - } - return getACL(item.getParent()); - } - - @Override - @Nonnull - @SuppressRestrictedWarnings(value = {IdStrategyComparator.class, AuthorizationContainer.class}) - public Set getGroups() { - Set r = new TreeSet<>(new IdStrategyComparator()); - r.addAll(super.getGroups()); - for (Job j : Jenkins.get().getAllItems(Job.class)) { - AzureAdAuthorizationMatrixProperty jobProperty = j.getProperty(AzureAdAuthorizationMatrixProperty.class); - if (jobProperty != null) { - r.addAll(jobProperty.getGroups()); - } - } - for (AbstractFolder j : Jenkins.get().getAllItems(AbstractFolder.class)) { - AzureAdAuthorizationMatrixFolderProperty folderProperty = - j.getProperties().get(AzureAdAuthorizationMatrixFolderProperty.class); - if (folderProperty != null) { - r.addAll(folderProperty.getGroups()); - } - } - return r; - } - - // Copy ended - - @Override - public void add(Permission p, String sid) { - super.add(p, sid); - objId2FullSidMap.putFullSid(sid); - } - - @Override - public boolean hasExplicitPermission(String sid, Permission p) { - // Jenkins will pass in the object Id as sid - final String objectId = sid; - if (objectId == null) { - return false; - } - return super.hasExplicitPermission(objId2FullSidMap.getOrOriginal(objectId), p); - } - - @Override - public boolean hasPermission(String sid, Permission p) { - // Jenkins will pass in the object Id as sid - final String objectId = sid; - return super.hasPermission(objId2FullSidMap.getOrOriginal(objectId), p); - } - - @Override - public boolean hasPermission(String sid, Permission p, boolean principal) { - // Jenkins will pass in the object Id as sid - final String objectId = sid; - return super.hasPermission(objId2FullSidMap.getOrOriginal(objectId), p, principal); - } - - @Extension - public static final Descriptor DESCRIPTOR = new DescriptorImpl(); - - - static AutoCompletionCandidates searchAndGenerateCandidates(String prefix) throws IOException { - final int maxCandidates = 20; - if (StringUtils.isEmpty(prefix)) { - return null; - } - - SecurityRealm realm = Jenkins.get().getSecurityRealm(); - if (!(realm instanceof AzureSecurityRealm)) { - return null; - } - Azure.Authenticated authenticated = ((AzureSecurityRealm) realm).getAzureClient(); - - List candidates = new ArrayList<>(); - LOGGER.info("search users with prefix: " + prefix); - try { - PagedList matchedUsers = authenticated.activeDirectoryUsers().inner() - .list(String.format("startswith(displayName,'%s') or startswith(mail, '%s')", prefix, prefix)); - for (UserInner user : matchedUsers.currentPage().items()) { - candidates.add(new AzureObject(user.objectId(), user.displayName())); - if (candidates.size() > maxCandidates) { - break; - } - } - - if (!matchedUsers.hasNextPage()) { - LOGGER.info("search groups with prefix " + prefix); - PagedList matchedGroups = authenticated.activeDirectoryGroups() - .inner().list("startswith(displayName,'" + prefix + "')"); - for (ADGroupInner group : matchedGroups.currentPage().items()) { - candidates.add(new AzureObject(group.objectId(), group.displayName())); - if (candidates.size() > maxCandidates) { - break; - } - } - } - } catch (GraphErrorException e) { - LOGGER.warning("Do not have sufficient privileges to search related users or groups"); - } - - AutoCompletionCandidates c = new AutoCompletionCandidates(); - for (AzureObject obj : candidates) { - String candidateText = ObjId2FullSidMap.generateFullSid(obj.getDisplayName(), obj.getObjectId()); - c.add(candidateText); - } - return c; - } - - public static class DescriptorImpl extends GlobalMatrixAuthorizationStrategy.DescriptorImpl { - @Override - protected GlobalMatrixAuthorizationStrategy create() { - return new AzureAdMatrixAuthorizationStrategy(); - } - - @Override - @Nonnull - public String getDisplayName() { - return "Azure Active Directory Matrix-based security"; - } - - public AutoCompletionCandidates doAutoCompleteUserOrGroup(@QueryParameter String value) throws IOException { - return searchAndGenerateCandidates(value); - } - } - - @Restricted(DoNotUse.class) - @SuppressRestrictedWarnings(GlobalMatrixAuthorizationStrategy.ConverterImpl.class) - public static class ConverterImpl extends GlobalMatrixAuthorizationStrategy.ConverterImpl { - @Override - public GlobalMatrixAuthorizationStrategy create() { - return new AzureAdMatrixAuthorizationStrategy(); - } - - @Override - @SuppressWarnings("rawtypes") - public boolean canConvert(Class type) { - return type == AzureAdMatrixAuthorizationStrategy.class; - } - } - - @Initializer(before = InitMilestone.PLUGINS_STARTED) - public static void fixClassNameTypo() { - // before 0.2.0 - Jenkins.XSTREAM2.addCompatibilityAlias( - "com.microsoft.jenkins.azuread.AzureAdMatrixAuthorizationStategy", - AzureAdMatrixAuthorizationStrategy.class); - } -} +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See LICENSE file in the project root for license information. + */ + +package com.microsoft.jenkins.azuread; + +import com.cloudbees.hudson.plugins.folder.AbstractFolder; +import com.microsoft.azure.PagedList; +import com.microsoft.azure.management.Azure; +import com.microsoft.azure.management.graphrbac.GraphErrorException; +import com.microsoft.azure.management.graphrbac.implementation.ADGroupInner; +import com.microsoft.azure.management.graphrbac.implementation.UserInner; +import hudson.Extension; +import hudson.init.InitMilestone; +import hudson.init.Initializer; +import hudson.model.AbstractItem; +import hudson.model.AutoCompletionCandidates; +import hudson.model.Descriptor; +import hudson.model.Item; +import hudson.model.ItemGroup; +import hudson.model.Job; +import hudson.security.ACL; +import hudson.security.AuthorizationStrategy; +import hudson.security.GlobalMatrixAuthorizationStrategy; +import hudson.security.Permission; +import hudson.security.SecurityRealm; +import hudson.security.SidACL; +import jenkins.model.Jenkins; +import org.acegisecurity.Authentication; +import org.apache.commons.lang.StringUtils; +import org.jenkinsci.plugins.matrixauth.AuthorizationContainer; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.DoNotUse; +import org.kohsuke.accmod.restrictions.NoExternalUse; +import org.kohsuke.accmod.restrictions.suppressions.SuppressRestrictedWarnings; +import org.kohsuke.stapler.QueryParameter; + +import javax.annotation.Nonnull; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.logging.Logger; + +public class AzureAdMatrixAuthorizationStrategy extends GlobalMatrixAuthorizationStrategy { + + private static final Logger LOGGER = Logger.getLogger(AzureAdMatrixAuthorizationStrategy.class.getName()); + + private final transient ObjId2FullSidMap objId2FullSidMap = new ObjId2FullSidMap(); + + // + // Inheriting from ProjectMatrixAuthorizationStrategy will lead to conflict + // of AzureAdAuthorizationMatrixProperty and AuthorizationMatrixProperty. + // Copy codes instead. + // + @Override + @Nonnull + public ACL getACL(@Nonnull Job project) { + AzureAdAuthorizationMatrixProperty amp = project.getProperty(AzureAdAuthorizationMatrixProperty.class); + if (amp != null) { + return amp.getInheritanceStrategy().getEffectiveACL(amp.getACL(), project); + } else { + return getACL(project.getParent()); + } + } + + @Restricted(NoExternalUse.class) + public static ACL inheritingACL(final ACL parent, final ACL child) { + if (parent instanceof SidACL && child instanceof SidACL) { + return ((SidACL) child).newInheritingACL((SidACL) parent); + } + return new ACL() { + @Override + public boolean hasPermission(@Nonnull Authentication a, @Nonnull Permission permission) { + return a.equals(SYSTEM) || child.hasPermission(a, permission) || parent.hasPermission(a, permission); + } + }; + } + + public ACL getACL(ItemGroup g) { + if (g instanceof Item) { + Item item = (Item) g; + return item.getACL(); + } + return getRootACL(); + } + + @Override + @Nonnull + public ACL getACL(@Nonnull AbstractItem item) { + if (Jenkins.get().getPlugin("cloudbees-folder") != null) { // optional dependency + if (item instanceof AbstractFolder) { + AzureAdAuthorizationMatrixFolderProperty p = + ((AbstractFolder) item).getProperties().get(AzureAdAuthorizationMatrixFolderProperty.class); + if (p != null) { + return p.getInheritanceStrategy().getEffectiveACL(p.getACL(), item); + } + } + } + return getACL(item.getParent()); + } + + @Override + @Nonnull + @SuppressRestrictedWarnings(value = {IdStrategyComparator.class, AuthorizationContainer.class}) + public Set getGroups() { + Set r = new TreeSet<>(new IdStrategyComparator()); + r.addAll(super.getGroups()); + for (Job j : Jenkins.get().getAllItems(Job.class)) { + AzureAdAuthorizationMatrixProperty jobProperty = j.getProperty(AzureAdAuthorizationMatrixProperty.class); + if (jobProperty != null) { + r.addAll(jobProperty.getGroups()); + } + } + for (AbstractFolder j : Jenkins.get().getAllItems(AbstractFolder.class)) { + AzureAdAuthorizationMatrixFolderProperty folderProperty = + j.getProperties().get(AzureAdAuthorizationMatrixFolderProperty.class); + if (folderProperty != null) { + r.addAll(folderProperty.getGroups()); + } + } + return r; + } + + // Copy ended + + @Override + public void add(Permission p, String sid) { + super.add(p, sid); + objId2FullSidMap.putFullSid(sid); + } + + @Override + public boolean hasExplicitPermission(String sid, Permission p) { + // Jenkins will pass in the object Id as sid + final String objectId = sid; + if (objectId == null) { + return false; + } + return super.hasExplicitPermission(objId2FullSidMap.getOrOriginal(objectId), p); + } + + @Override + public boolean hasPermission(String sid, Permission p) { + // Jenkins will pass in the object Id as sid + final String objectId = sid; + return super.hasPermission(objId2FullSidMap.getOrOriginal(objectId), p); + } + + @Override + public boolean hasPermission(String sid, Permission p, boolean principal) { + // Jenkins will pass in the object Id as sid + final String objectId = sid; + return super.hasPermission(objId2FullSidMap.getOrOriginal(objectId), p, principal); + } + + @Extension + public static final Descriptor DESCRIPTOR = new DescriptorImpl(); + + + static AutoCompletionCandidates searchAndGenerateCandidates(String prefix) throws IOException { + final int maxCandidates = 20; + if (StringUtils.isEmpty(prefix)) { + return null; + } + + SecurityRealm realm = Jenkins.get().getSecurityRealm(); + if (!(realm instanceof AzureSecurityRealm)) { + return null; + } + Azure.Authenticated authenticated = ((AzureSecurityRealm) realm).getAzureClient(); + + List candidates = new ArrayList<>(); + LOGGER.info("search users with prefix: " + prefix); + try { + PagedList matchedUsers = authenticated.activeDirectoryUsers().inner() + .list(String.format("startswith(displayName,'%s') or startswith(mail, '%s')", prefix, prefix)); + for (UserInner user : matchedUsers.currentPage().items()) { + candidates.add(new AzureObject(user.objectId(), user.displayName())); + if (candidates.size() > maxCandidates) { + break; + } + } + + if (!matchedUsers.hasNextPage()) { + LOGGER.info("search groups with prefix " + prefix); + PagedList matchedGroups = authenticated.activeDirectoryGroups() + .inner().list("startswith(displayName,'" + prefix + "')"); + for (ADGroupInner group : matchedGroups.currentPage().items()) { + candidates.add(new AzureObject(group.objectId(), group.displayName())); + if (candidates.size() > maxCandidates) { + break; + } + } + } + } catch (GraphErrorException e) { + LOGGER.warning("Do not have sufficient privileges to search related users or groups"); + } + + AutoCompletionCandidates c = new AutoCompletionCandidates(); + for (AzureObject obj : candidates) { + String candidateText = ObjId2FullSidMap.generateFullSid(obj.getDisplayName(), obj.getObjectId()); + c.add(candidateText); + } + return c; + } + + public static class DescriptorImpl extends GlobalMatrixAuthorizationStrategy.DescriptorImpl { + @Override + protected GlobalMatrixAuthorizationStrategy create() { + return new AzureAdMatrixAuthorizationStrategy(); + } + + @Override + @Nonnull + public String getDisplayName() { + return "Azure Active Directory Matrix-based security"; + } + + public AutoCompletionCandidates doAutoCompleteUserOrGroup(@QueryParameter String value) throws IOException { + return searchAndGenerateCandidates(value); + } + } + + @Restricted(DoNotUse.class) + @SuppressRestrictedWarnings(GlobalMatrixAuthorizationStrategy.ConverterImpl.class) + public static class ConverterImpl extends GlobalMatrixAuthorizationStrategy.ConverterImpl { + @Override + public GlobalMatrixAuthorizationStrategy create() { + return new AzureAdMatrixAuthorizationStrategy(); + } + + @Override + @SuppressWarnings("rawtypes") + public boolean canConvert(Class type) { + return type == AzureAdMatrixAuthorizationStrategy.class; + } + } + + @Initializer(before = InitMilestone.PLUGINS_STARTED) + public static void fixClassNameTypo() { + // before 0.2.0 + Jenkins.XSTREAM2.addCompatibilityAlias( + "com.microsoft.jenkins.azuread.AzureAdMatrixAuthorizationStategy", + AzureAdMatrixAuthorizationStrategy.class); + } +} diff --git a/src/main/java/com/microsoft/jenkins/azuread/AzureAdUser.java b/src/main/java/com/microsoft/jenkins/azuread/AzureAdUser.java index 0bd21584..f1108fc3 100644 --- a/src/main/java/com/microsoft/jenkins/azuread/AzureAdUser.java +++ b/src/main/java/com/microsoft/jenkins/azuread/AzureAdUser.java @@ -118,26 +118,42 @@ public void setAuthorities(Collection groups) { @SuppressWarnings({"checkstyle:needbraces"}) @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } AzureAdUser that = (AzureAdUser) o; - if (!Objects.equals(name, that.name)) return false; - if (!Objects.equals(givenName, that.givenName)) return false; - if (!Objects.equals(familyName, that.familyName)) return false; - if (!Objects.equals(uniqueName, that.uniqueName)) return false; - if (!Objects.equals(tenantID, that.tenantID)) return false; + if (!Objects.equals(name, that.name)) { + return false; + } + if (!Objects.equals(givenName, that.givenName)) { + return false; + } + if (!Objects.equals(familyName, that.familyName)) { + return false; + } + if (!Objects.equals(uniqueName, that.uniqueName)) { + return false; + } + if (!Objects.equals(tenantID, that.tenantID)) { + return false; + } if (groupOIDs != null && that.groupOIDs != null) { - if (!CollectionUtils.isEqualCollection(groupOIDs, that.groupOIDs)) return false; + if (!CollectionUtils.isEqualCollection(groupOIDs, that.groupOIDs)) { + return false; + } } else if (groupOIDs != null || that.groupOIDs != null) { return false; } return objectID.equals(that.objectID); } - @SuppressWarnings({"checkstyle:magicnumber"}) @Override + @SuppressWarnings("checkstyle:magicnumber") public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + (givenName != null ? givenName.hashCode() : 0); diff --git a/src/main/java/com/microsoft/jenkins/azuread/scribe/AzureJsonTokenExtractor.java b/src/main/java/com/microsoft/jenkins/azuread/scribe/AzureJsonTokenExtractor.java index cda644bd..9fc7baac 100644 --- a/src/main/java/com/microsoft/jenkins/azuread/scribe/AzureJsonTokenExtractor.java +++ b/src/main/java/com/microsoft/jenkins/azuread/scribe/AzureJsonTokenExtractor.java @@ -1,36 +1,36 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See LICENSE file in the project root for license information. - */ - -package com.microsoft.jenkins.azuread.scribe; - -import com.github.scribejava.core.exceptions.OAuthException; -import com.github.scribejava.core.extractors.TokenExtractor; -import com.github.scribejava.core.model.OAuth2AccessToken; -import com.github.scribejava.core.model.Response; -import com.github.scribejava.core.utils.Preconditions; -import com.microsoft.jenkins.azuread.Utils; - -import java.io.IOException; - -public class AzureJsonTokenExtractor implements TokenExtractor { - - private static class InstanceHolder { - private static final AzureJsonTokenExtractor INSTANCE = new AzureJsonTokenExtractor(); - } - - public static AzureJsonTokenExtractor instance() { - return InstanceHolder.INSTANCE; - } - - protected AzureJsonTokenExtractor() { - } - - @Override - public OAuth2AccessToken extract(Response response) throws IOException, OAuthException { - Preconditions.checkEmptyString(response.getBody(), - "Response body is incorrect. Can't extract a token from an empty string"); - return Utils.JsonUtil.fromJson(response.getBody(), AzureToken.class); - } -} +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See LICENSE file in the project root for license information. + */ + +package com.microsoft.jenkins.azuread.scribe; + +import com.github.scribejava.core.exceptions.OAuthException; +import com.github.scribejava.core.extractors.TokenExtractor; +import com.github.scribejava.core.model.OAuth2AccessToken; +import com.github.scribejava.core.model.Response; +import com.github.scribejava.core.utils.Preconditions; +import com.microsoft.jenkins.azuread.Utils; + +import java.io.IOException; + +public class AzureJsonTokenExtractor implements TokenExtractor { + + private static class InstanceHolder { + private static final AzureJsonTokenExtractor INSTANCE = new AzureJsonTokenExtractor(); + } + + public static AzureJsonTokenExtractor instance() { + return InstanceHolder.INSTANCE; + } + + protected AzureJsonTokenExtractor() { + } + + @Override + public OAuth2AccessToken extract(Response response) throws IOException, OAuthException { + Preconditions.checkEmptyString(response.getBody(), + "Response body is incorrect. Can't extract a token from an empty string"); + return Utils.JsonUtil.fromJson(response.getBody(), AzureToken.class); + } +} diff --git a/src/main/java/com/microsoft/jenkins/azuread/scribe/AzureOAuthService.java b/src/main/java/com/microsoft/jenkins/azuread/scribe/AzureOAuthService.java index 35e69cc1..d57229bf 100644 --- a/src/main/java/com/microsoft/jenkins/azuread/scribe/AzureOAuthService.java +++ b/src/main/java/com/microsoft/jenkins/azuread/scribe/AzureOAuthService.java @@ -1,58 +1,58 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See LICENSE file in the project root for license information. - */ - -package com.microsoft.jenkins.azuread.scribe; - -import com.github.scribejava.core.model.OAuth2AccessToken; -import com.github.scribejava.core.model.OAuthConfig; -import com.github.scribejava.core.model.OAuthConstants; -import com.github.scribejava.core.model.OAuthRequest; -import com.github.scribejava.core.oauth.OAuth20Service; - -import java.io.IOException; -import java.util.concurrent.ExecutionException; - -public class AzureOAuthService extends OAuth20Service { - - public AzureOAuthService(AzureApi api, OAuthConfig config) { - super(api, config); - } - - @Override - protected OAuthRequest createAccessTokenRequest(String code) { - OAuthRequest request = super.createAccessTokenRequest(code); - request.addParameter("resource", getApi().getResource()); - return request; - } - - protected OAuthRequest createAccessTokenCredentialGrantRequest() { - final OAuthRequest request = new OAuthRequest(getApi().getAccessTokenVerb(), getApi().getAccessTokenEndpoint()); - final OAuthConfig config = getConfig(); - request.addParameter(OAuthConstants.CLIENT_ID, config.getApiKey()); - request.addParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret()); - request.addParameter(OAuthConstants.SCOPE, config.getScope()); - request.addParameter(OAuthConstants.GRANT_TYPE, "client_credentials"); - return request; - } - - public OAuth2AccessToken getAccessTokenCredentialGrant() - throws InterruptedException, ExecutionException, IOException { - final OAuthRequest request = createAccessTokenCredentialGrantRequest(); - return sendAccessTokenRequestSync(request); - } - - @Override - public AzureApi getApi() { - return (AzureApi) super.getApi(); - } - - public final String getLogoutUrl() { - return getLogoutUrl(null); - } - - public String getLogoutUrl(String postLogoutUrl) { - return getApi().getLogoutUrl(postLogoutUrl); - } -} +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See LICENSE file in the project root for license information. + */ + +package com.microsoft.jenkins.azuread.scribe; + +import com.github.scribejava.core.model.OAuth2AccessToken; +import com.github.scribejava.core.model.OAuthConfig; +import com.github.scribejava.core.model.OAuthConstants; +import com.github.scribejava.core.model.OAuthRequest; +import com.github.scribejava.core.oauth.OAuth20Service; + +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +public class AzureOAuthService extends OAuth20Service { + + public AzureOAuthService(AzureApi api, OAuthConfig config) { + super(api, config); + } + + @Override + protected OAuthRequest createAccessTokenRequest(String code) { + OAuthRequest request = super.createAccessTokenRequest(code); + request.addParameter("resource", getApi().getResource()); + return request; + } + + protected OAuthRequest createAccessTokenCredentialGrantRequest() { + final OAuthRequest request = new OAuthRequest(getApi().getAccessTokenVerb(), getApi().getAccessTokenEndpoint()); + final OAuthConfig config = getConfig(); + request.addParameter(OAuthConstants.CLIENT_ID, config.getApiKey()); + request.addParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret()); + request.addParameter(OAuthConstants.SCOPE, config.getScope()); + request.addParameter(OAuthConstants.GRANT_TYPE, "client_credentials"); + return request; + } + + public OAuth2AccessToken getAccessTokenCredentialGrant() + throws InterruptedException, ExecutionException, IOException { + final OAuthRequest request = createAccessTokenCredentialGrantRequest(); + return sendAccessTokenRequestSync(request); + } + + @Override + public AzureApi getApi() { + return (AzureApi) super.getApi(); + } + + public final String getLogoutUrl() { + return getLogoutUrl(null); + } + + public String getLogoutUrl(String postLogoutUrl) { + return getApi().getLogoutUrl(postLogoutUrl); + } +} diff --git a/src/main/java/com/microsoft/jenkins/azuread/scribe/AzureToken.java b/src/main/java/com/microsoft/jenkins/azuread/scribe/AzureToken.java index 1c4a0077..d91c1b6a 100644 --- a/src/main/java/com/microsoft/jenkins/azuread/scribe/AzureToken.java +++ b/src/main/java/com/microsoft/jenkins/azuread/scribe/AzureToken.java @@ -31,8 +31,8 @@ public AzureToken(@JsonProperty("access_token") String accessToken, this.idToken = idToken; } - @SuppressWarnings({"checkstyle:magicnumber"}) @Override + @SuppressWarnings("checkstyle:magicnumber") public int hashCode() { int hash = super.hashCode(); hash = 41 * hash + Objects.hashCode(idToken);