diff --git a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/transport/MavenAuthenticator.java b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/transport/MavenAuthenticator.java index be66fb2b70..fd5751c746 100644 --- a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/transport/MavenAuthenticator.java +++ b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/transport/MavenAuthenticator.java @@ -18,11 +18,13 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.util.ArrayList; import java.util.Base64; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Stack; import java.util.function.BiConsumer; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -32,6 +34,7 @@ import org.apache.maven.project.MavenProject; import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Requirement; +import org.codehaus.plexus.logging.Logger; import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable; import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException; import org.eclipse.tycho.IRepositoryIdManager; @@ -46,6 +49,7 @@ public class MavenAuthenticator extends Authenticator implements Initializable { static final String PROXY_AUTHORIZATION_HEADER = "Proxy-Authorization"; static final String AUTHORIZATION_HEADER = "Authorization"; + private ThreadLocal> locationStack = ThreadLocal.withInitial(Stack::new); @Requirement LegacySupport legacySupport; @@ -59,28 +63,63 @@ public class MavenAuthenticator extends Authenticator implements Initializable { @Requirement MavenRepositorySettings mavenRepositorySettings; + @Requirement + Logger log; + private List repositoryLocations; - public Credentials getServerCredentials(URI uri) { + public Credentials getServerCredentials(URI requestUri) { + List list = new ArrayList<>(locationStack.get()); + Collections.reverse(list); + Stream repoStream = list.stream().takeWhile(repo -> repo.getHost().equals(requestUri.getHost())); + List locations = getMavenLocations(); + return Stream.concat(Stream.of(requestUri), repoStream).flatMap(uri -> { + log.info("Fetching credentials for " + uri); + return locations.stream().filter(loc -> { + String prefix = loc.getURL().normalize().toASCIIString(); + String match = uri.normalize().toASCIIString(); + if (match.startsWith(prefix)) { + log.info("Found matching " + loc); + return true; + } + log.info(loc + " does not match (prefix = " + prefix + ", to match = " + match + ")"); + return false; + }); + }).map(mavenRepositorySettings::getCredentials).filter(Objects::nonNull).findFirst().orElse(null); + } + + private List getMavenLocations() { Stream locations = repositoryLocations.stream(); locations = Stream.concat(locations, repositoryIdManager.getKnownMavenRepositoryLocations()); - String requestUri = uri.normalize().toASCIIString(); - return locations.sorted((loc1, loc2) -> { + List sorted = locations.sorted((loc1, loc2) -> { // we wan't the longest prefix match, so first sort all uris by their length ... String s1 = loc1.getURL().normalize().toASCIIString(); String s2 = loc2.getURL().normalize().toASCIIString(); return Long.compare(s2.length(), s1.length()); - }).filter(loc -> { - String prefix = loc.getURL().normalize().toASCIIString(); - return requestUri.startsWith(prefix); - }).map(mavenRepositorySettings::getCredentials).filter(Objects::nonNull).findFirst().orElse(null); + }).toList(); + return sorted; } - public void preemtiveAuth(BiConsumer headerConsumer, URI uri) { + public Authenticator preemtiveAuth(BiConsumer headerConsumer, URI uri) { // as everything is known and we can't ask the user anyways, preemtive auth is a // good choice here to prevent successive requests - addAuthHeader(headerConsumer, getAuth(RequestorType.PROXY, uri), PROXY_AUTHORIZATION_HEADER); - addAuthHeader(headerConsumer, getAuth(RequestorType.SERVER, uri), AUTHORIZATION_HEADER); + PasswordAuthentication proxyAuth = getAuth(RequestorType.PROXY, uri); + PasswordAuthentication serverAuth = getAuth(RequestorType.SERVER, uri); + addAuthHeader(headerConsumer, proxyAuth, PROXY_AUTHORIZATION_HEADER); + addAuthHeader(headerConsumer, serverAuth, AUTHORIZATION_HEADER); + return new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + RequestorType type = getRequestorType(); + if (type == RequestorType.PROXY) { + return proxyAuth; + } + if (type == RequestorType.SERVER) { + return serverAuth; + } + return null; + } + }; } @Override @@ -139,4 +178,14 @@ public void initialize() throws InitializationException { } + public void enterLoad(URI location) { + log.info("Enter loading repository " + location); + locationStack.get().push(location); + } + + public void exitLoad() { + URI pop = locationStack.get().pop(); + log.info("Exit loading repository " + pop); + } + } diff --git a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/transport/RemoteArtifactRepositoryManager.java b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/transport/RemoteArtifactRepositoryManager.java index d136d93c11..0f4ebb9c6e 100644 --- a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/transport/RemoteArtifactRepositoryManager.java +++ b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/transport/RemoteArtifactRepositoryManager.java @@ -30,20 +30,19 @@ class RemoteArtifactRepositoryManager implements IArtifactRepositoryManager { private IArtifactRepositoryManager delegate; private final IRepositoryIdManager loadingHelper; + private MavenAuthenticator authenticator; - RemoteArtifactRepositoryManager(IArtifactRepositoryManager delegate, IRepositoryIdManager loadingHelper) { + RemoteArtifactRepositoryManager(IArtifactRepositoryManager delegate, IRepositoryIdManager loadingHelper, + MavenAuthenticator authenticator) { this.delegate = delegate; this.loadingHelper = loadingHelper; + this.authenticator = authenticator; } private URI translate(URI location) { return loadingHelper.getEffectiveLocation(location); } - private URI translateAndPrepareLoad(URI location) throws ProvisionException { - return loadingHelper.getEffectiveLocationAndPrepareLoad(location); - } - @Override public void addRepository(URI location) { delegate.addRepository(translate(location)); @@ -98,12 +97,12 @@ public boolean isEnabled(URI location) { @Override public IArtifactRepository loadRepository(URI location, int flags, IProgressMonitor monitor) throws ProvisionException { - return delegate.loadRepository(translateAndPrepareLoad(location), flags, monitor); + return accessRepository(location, uri -> delegate.loadRepository(uri, flags, monitor)); } @Override public IArtifactRepository loadRepository(URI location, IProgressMonitor monitor) throws ProvisionException { - return delegate.loadRepository(translateAndPrepareLoad(location), monitor); + return accessRepository(location, uri -> delegate.loadRepository(uri, monitor)); } @Override @@ -113,7 +112,7 @@ public IQueryResult query(IQuery query, IProgressMon @Override public IArtifactRepository refreshRepository(URI location, IProgressMonitor monitor) throws ProvisionException { - return delegate.refreshRepository(translateAndPrepareLoad(location), monitor); + return accessRepository(location, uri -> delegate.refreshRepository(uri, monitor)); } @Override @@ -131,4 +130,20 @@ public void setRepositoryProperty(URI location, String key, String value) { delegate.setRepositoryProperty(translate(location), key, value); } + public V accessRepository(URI initialUri, RepositoryCallable action) throws ProvisionException { + URI effectiveURI = loadingHelper.getEffectiveLocationAndPrepareLoad(initialUri); + authenticator.enterLoad(effectiveURI); + try { + return action.call(effectiveURI); + } finally { + authenticator.exitLoad(); + } + } + + private static interface RepositoryCallable { + + V call(URI effectiveURI) throws ProvisionException; + + } + } diff --git a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/transport/RemoteArtifactRepositoryManagerAgentFactory.java b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/transport/RemoteArtifactRepositoryManagerAgentFactory.java index 469c696300..c936a1669c 100644 --- a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/transport/RemoteArtifactRepositoryManagerAgentFactory.java +++ b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/transport/RemoteArtifactRepositoryManagerAgentFactory.java @@ -30,6 +30,9 @@ public class RemoteArtifactRepositoryManagerAgentFactory implements IAgentServic @Requirement IRepositoryIdManager repositoryIdManager; + @Requirement + MavenAuthenticator authenticator; + @Override public Object createService(IProvisioningAgent agent) { IArtifactRepositoryManager plainRepoManager = (IArtifactRepositoryManager) new ArtifactRepositoryComponent() @@ -38,7 +41,7 @@ public Object createService(IProvisioningAgent agent) { plainRepoManager = new P2MirrorDisablingArtifactRepositoryManager(plainRepoManager, logger); } - return new RemoteArtifactRepositoryManager(plainRepoManager, repositoryIdManager); + return new RemoteArtifactRepositoryManager(plainRepoManager, repositoryIdManager, authenticator); } private boolean getDisableP2MirrorsConfiguration() { diff --git a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/transport/RemoteMetadataRepositoryManager.java b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/transport/RemoteMetadataRepositoryManager.java index bc555d16ae..cb1f1ee963 100644 --- a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/transport/RemoteMetadataRepositoryManager.java +++ b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/transport/RemoteMetadataRepositoryManager.java @@ -32,121 +32,126 @@ class RemoteMetadataRepositoryManager implements IMetadataRepositoryManager { - private final IMetadataRepositoryManager delegate; - private final IRepositoryIdManager loadingHelper; + private final IMetadataRepositoryManager delegate; + private final IRepositoryIdManager loadingHelper; private final Logger logger; - - RemoteMetadataRepositoryManager(IMetadataRepositoryManager delegate, IRepositoryIdManager loadingHelper, - Logger logger) { - this.delegate = delegate; - this.loadingHelper = Objects.requireNonNull(loadingHelper); - this.logger = logger; - } - - private URI translate(URI location) { - return loadingHelper.getEffectiveLocation(location); - } - - private URI translateAndPrepareLoad(URI location) throws ProvisionException { - return loadingHelper.getEffectiveLocationAndPrepareLoad(location); - } - - @Override - public IMetadataRepository loadRepository(URI location, IProgressMonitor monitor) - throws ProvisionException, OperationCanceledException { - return this.loadRepository(location, IRepository.NONE, monitor); - } - - @Override - public IMetadataRepository loadRepository(URI location, int flags, IProgressMonitor monitor) - throws ProvisionException, OperationCanceledException { - URI effectiveLocation = translateAndPrepareLoad(location); - - IMetadataRepository loadedRepository = delegate.loadRepository(effectiveLocation, flags, monitor); - failIfRepositoryContainsPartialIUs(loadedRepository, effectiveLocation); - - return loadedRepository; - } - - private void failIfRepositoryContainsPartialIUs(IMetadataRepository repository, URI effectiveLocation) - throws ProvisionException { - IQueryResult allUnits = repository.query(QueryUtil.ALL_UNITS, null); - boolean hasPartialIUs = false; - for (IInstallableUnit unit : allUnits.toUnmodifiableSet()) { - if (Boolean.valueOf(unit.getProperty(IInstallableUnit.PROP_PARTIAL_IU))) { - hasPartialIUs = true; - logger.error("Partial IU: " + unit.getId()); - } - } - if (hasPartialIUs) { - String message = "The p2 repository at " + effectiveLocation - + " contains partial IUs (see above) from an old style update site which cannot be used for dependency resolution"; - throw new ProvisionException(message); - } - } - - // delegated methods - - @Override - public void addRepository(URI location) { - delegate.addRepository(translate(location)); - } - - @Override - public boolean contains(URI location) { - return delegate.contains(translate(location)); - } - - @Override - public IMetadataRepository createRepository(URI location, String name, String type, Map properties) - throws ProvisionException, OperationCanceledException { - return delegate.createRepository(translate(location), name, type, properties); - } - - @Override - public IProvisioningAgent getAgent() { - return delegate.getAgent(); - } - - @Override - public URI[] getKnownRepositories(int flags) { - return delegate.getKnownRepositories(flags); - } - - @Override - public String getRepositoryProperty(URI location, String key) { - return delegate.getRepositoryProperty(translate(location), key); - } - - @Override - public boolean isEnabled(URI location) { - return delegate.isEnabled(translate(location)); - } - - @Override - public IQueryResult query(IQuery query, IProgressMonitor monitor) { - return delegate.query(query, monitor); - } - - @Override - public IMetadataRepository refreshRepository(URI location, IProgressMonitor monitor) - throws ProvisionException, OperationCanceledException { - return delegate.refreshRepository(translateAndPrepareLoad(location), monitor); - } - - @Override - public boolean removeRepository(URI location) { - return delegate.removeRepository(translate(location)); - } - - @Override - public void setEnabled(URI location, boolean enablement) { - delegate.setEnabled(translate(location), enablement); - } - - @Override - public void setRepositoryProperty(URI location, String key, String value) { - delegate.setRepositoryProperty(translate(location), key, value); - } + private MavenAuthenticator authenticator; + + RemoteMetadataRepositoryManager(IMetadataRepositoryManager delegate, IRepositoryIdManager loadingHelper, + Logger logger, MavenAuthenticator authenticator) { + this.delegate = delegate; + this.authenticator = authenticator; + this.loadingHelper = Objects.requireNonNull(loadingHelper); + this.logger = logger; + } + + private URI translate(URI location) { + return loadingHelper.getEffectiveLocation(location); + } + + private URI translateAndPrepareLoad(URI location) throws ProvisionException { + return loadingHelper.getEffectiveLocationAndPrepareLoad(location); + } + + @Override + public IMetadataRepository loadRepository(URI location, IProgressMonitor monitor) + throws ProvisionException, OperationCanceledException { + return this.loadRepository(location, IRepository.NONE, monitor); + } + + @Override + public IMetadataRepository loadRepository(URI location, int flags, IProgressMonitor monitor) + throws ProvisionException, OperationCanceledException { + URI effectiveLocation = translateAndPrepareLoad(location); + authenticator.enterLoad(location); + try { + IMetadataRepository loadedRepository = delegate.loadRepository(effectiveLocation, flags, monitor); + failIfRepositoryContainsPartialIUs(loadedRepository, effectiveLocation); + return loadedRepository; + } finally { + authenticator.exitLoad(); + } + } + + private void failIfRepositoryContainsPartialIUs(IMetadataRepository repository, URI effectiveLocation) + throws ProvisionException { + IQueryResult allUnits = repository.query(QueryUtil.ALL_UNITS, null); + boolean hasPartialIUs = false; + for (IInstallableUnit unit : allUnits.toUnmodifiableSet()) { + if (Boolean.valueOf(unit.getProperty(IInstallableUnit.PROP_PARTIAL_IU))) { + hasPartialIUs = true; + logger.error("Partial IU: " + unit.getId()); + } + } + if (hasPartialIUs) { + String message = "The p2 repository at " + effectiveLocation + + " contains partial IUs (see above) from an old style update site which cannot be used for dependency resolution"; + throw new ProvisionException(message); + } + } + + // delegated methods + + @Override + public void addRepository(URI location) { + delegate.addRepository(translate(location)); + } + + @Override + public boolean contains(URI location) { + return delegate.contains(translate(location)); + } + + @Override + public IMetadataRepository createRepository(URI location, String name, String type, Map properties) + throws ProvisionException, OperationCanceledException { + return delegate.createRepository(translate(location), name, type, properties); + } + + @Override + public IProvisioningAgent getAgent() { + return delegate.getAgent(); + } + + @Override + public URI[] getKnownRepositories(int flags) { + return delegate.getKnownRepositories(flags); + } + + @Override + public String getRepositoryProperty(URI location, String key) { + return delegate.getRepositoryProperty(translate(location), key); + } + + @Override + public boolean isEnabled(URI location) { + return delegate.isEnabled(translate(location)); + } + + @Override + public IQueryResult query(IQuery query, IProgressMonitor monitor) { + return delegate.query(query, monitor); + } + + @Override + public IMetadataRepository refreshRepository(URI location, IProgressMonitor monitor) + throws ProvisionException, OperationCanceledException { + return delegate.refreshRepository(translateAndPrepareLoad(location), monitor); + } + + @Override + public boolean removeRepository(URI location) { + return delegate.removeRepository(translate(location)); + } + + @Override + public void setEnabled(URI location, boolean enablement) { + delegate.setEnabled(translate(location), enablement); + } + + @Override + public void setRepositoryProperty(URI location, String key, String value) { + delegate.setRepositoryProperty(translate(location), key, value); + } } diff --git a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/transport/RemoteMetadataRepositoryManagerAgentFactory.java b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/transport/RemoteMetadataRepositoryManagerAgentFactory.java index 5b5dc8315b..993e54026e 100644 --- a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/transport/RemoteMetadataRepositoryManagerAgentFactory.java +++ b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/transport/RemoteMetadataRepositoryManagerAgentFactory.java @@ -30,11 +30,15 @@ public class RemoteMetadataRepositoryManagerAgentFactory implements IAgentServic @Requirement IRepositoryIdManager repositoryIdManager; + @Requirement + MavenAuthenticator mavenAuthenticator; + @Override public Object createService(IProvisioningAgent agent) { IMetadataRepositoryManager plainMetadataRepoManager = (IMetadataRepositoryManager) new MetadataRepositoryComponent() .createService(agent); - return new RemoteMetadataRepositoryManager(plainMetadataRepoManager, repositoryIdManager, logger); + return new RemoteMetadataRepositoryManager(plainMetadataRepoManager, repositoryIdManager, logger, + mavenAuthenticator); } } diff --git a/tycho-api/src/main/java/org/eclipse/tycho/MavenRepositorySettings.java b/tycho-api/src/main/java/org/eclipse/tycho/MavenRepositorySettings.java index be191d5265..68286e8df3 100644 --- a/tycho-api/src/main/java/org/eclipse/tycho/MavenRepositorySettings.java +++ b/tycho-api/src/main/java/org/eclipse/tycho/MavenRepositorySettings.java @@ -43,6 +43,11 @@ public String getPassword() { public URI getURI() { return url; } + + @Override + public String toString() { + return "Credentials for " + getURI(); + } } /**