SBT是否支持抢占式身份验证以下载软件包?

时间:2020-05-15 16:50:24

标签: scala sbt artifactory ivy coursier

我正在运行SBT 1.2.8,我的项目需要从私有托管的Artifactory实例上的存储库中下载软件包。我的仓库受基本身份验证保护。阅读了大量示例和说明之后,我在我的仓库中创建了一个credentials.properties文件。

realm=Artifactory Realm
host=artifactory.mycompany.com
username=my_username
password=my_password

然后我将以下内容添加到我的build.sbt文件中

credentials += Credentials(new File("credentials.properties"))

然后我将存储库添加到resolvers.sbt

中的解析器列表中
"My Company Artifactory" at "https://artifactory.mycompany.com/artifactory/my_private_repo/",

我构建了我的应用程序,并能够很好地下载受保护的程序包。

但是,我公司的系统管理员要求我打开Artifactory中的“隐藏未授权资源的存在”设置。当未经身份验证的用户尝试访问受保护的资源时,此设置将强制Artifactory返回404错误。通常在这种情况下,Artifactory返回带有WWW-Authenticate标头的401s。

突然,我的应用程序无法解析其依赖项。我关闭了Artifactory设置,然后再次打开,并确认该设置实际上是导致我出现问题的原因。

除非SBT受到401和WWW-Authenticate头(具有适当的域)的挑战,否则似乎不会发送凭据。查看SBT,Ivy和Coursier的文档和GitHub问题,似乎这种“抢先式身份验证”不受支持。

我花了很多时间试图以各种方式解决此问题,但找不到解决方案。这是我尝试过的:

  • 将我的Artifactory用户名和密码添加到存储库URL,因此看起来像https://my_username:my_password@artifactory.mycompany.com/artifactory/my_private_repo/。这在我的浏览器和REST客户端中有效,但不适用于SBT。
  • 从我的凭据文件中删除“领域”
  • 切换到SBT 1.3.9并尝试使用新版本进行上述所有操作。

有人知道我如何让SBT使用抢占式HTTP基本身份验证吗?看来Maven和Gradle都支持此功能(请参阅下面的链接),但是我在SBT文档中找不到任何内容。

对抢占式身份验证的Maven支持:https://jfrog.com/knowledge-base/why-does-my-maven-builds-are-failing-with-a-404-error-when-hide-existence-of-unauthorized-resources-is-enabled/

对抢占式身份验证的分级支持: https://github.com/gradle/gradle/pull/386/files

我几乎要考虑设置一个本地代理以发送适当的标头Artifactory,并指出SBT将该本地代理用作解析器。但是,对于开发人员而言,这似乎不必要。

1 个答案:

答案 0 :(得分:0)

你说得对。

您可以设置一个 AbstractRepository。参见 https://github.com/SupraFii/sbt-google-artifact-registry/blob/master/src/main/scala/ch/firsts/sbt/gar/ArtifactRegistryRepository.scala#L21 示例:

package ch.firsts.sbt.gar

import java.io.File
import java.util

import com.google.cloud.artifactregistry.wagon.ArtifactRegistryWagon
import org.apache.ivy.core.module.descriptor.Artifact
import org.apache.ivy.plugins.repository.AbstractRepository
import org.apache.maven.wagon.repository.Repository

class ArtifactRegistryRepository(repositoryUrl: String) extends AbstractRepository {
  val repo = new Repository("google-artifact-registry", repositoryUrl)
  val wagon = new ArtifactRegistryWagon()

  override def getResource(source: String): ArtifactRegistryResource = {
    val plainSource = stripRepository(source)
    wagon.connect(repo)
    ArtifactRegistryResource(repositoryUrl, plainSource, wagon.resourceExists(plainSource))
  }

  override def get(source: String, destination: File): Unit = {
    val adjustedSource = if (destination.toString.endsWith("sha1"))
      source + ".sha1"
    else if (destination.toString.endsWith("md5"))
      source + ".md5"
    else
      source

    wagon.connect(repo)
    wagon.get(adjustedSource, destination)
  }

  override def list(parent: String): util.List[String] = sys.error("Listing repository contents is not supported")

  override def put(artifact: Artifact, source: File, destination: String, overwrite: Boolean): Unit = {
    val plainDestination = stripRepository(destination)
    wagon.connect(repo)
    wagon.put(source, plainDestination)
  }

  private def stripRepository(fullName: String): String = fullName.substring(repositoryUrl.length + 1)

}