sbt: publish to corporate Nexus repository unautho

2020-05-14 10:11发布

问题:

Quick resolution

The required credential expects the exact realm as defined by nexus. See below how to find the one you have defined, but most certainly is "Sonatype Nexus Repository Manager". Add the rest of the details to the credentials as normal.

c:/data/user/.sbt/.credentials

realm=Sonatype Nexus Repository Manager
host=nexus
user=repouser
password=password

build.sbt credentials += Credentials(Path.userHome / ".sbt" / ".credentials")

publishTo <<= version { v: String =>
  val nexus = "http://nexus/" 
  if (v.trim.endsWith("SNAPSHOT"))
    Some("snapshots" at nexus + "content/repositories/libs-snapshots")
  else
    Some("releases" at nexus + "content/repositories/libs-releases")
  }

Problem

I'm trying to publish a jar into a corporate nexus repo.

I'm able to do this fine from Maven, and I have configured the repositories to be able to use Nexus to provide internal jars. However, publication fails due to authorization.

> publish
[info] Packaging c:\app\target\scala-2.10\app_2.10-0.1-sources.jar ...
[info] Wrote D:\app\target\scala-2.10\app_2.10-0.1.pom
[info] :: delivering :: com.app#app_2.10;0.1 :: 0.1 :: release :: Tue May 07 18:28:44 BST     2013
[info] Done packaging.
[info]  delivering ivy file to D:\app\target\scala-2.10\ivy-0.1.xml
[info] Packaging D:\app\target\scala-2.10\app_2.10-0.1.jar ...
[info] Done packaging.
[trace] Stack trace suppressed: run last *:publish for the full output.
[error] (*:publish) java.io.IOException: Access to URL http://nexus/content/groups/common/com/app/app_2.10/0.1/app_2.10-0.1.pom was refused by the server: Unauthorized

c:/data/user/.sbt/.credentials

realm=X 
host=nexus
user=repouser
password=password

c:/data/user/.sbt/repositories

 [repositories]
  local
  x-repo: http://nexus/content/groups/common
  typesafe-ivy-releases: http://repo.typesafe.com/typesafe/ivy-releases/,     [organization]/[module]/[revision]/[type]s/[artifact](-[classifier]).[ext]   
  sbt-plugin-releases: http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases/
  maven-central

app/build.sbt

 name := "app"

 organization := "com.app"

 version := "0.1"

 scalaVersion := "2.10.1"

 libraryDependencies ++= Seq(
"org.scalatest" % "scalatest_2.10" % "2.0.M5b" % "test"
 )

 EclipseKeys.withSource := true

 publishMavenStyle := true

 credentials += Credentials(Path.userHome / ".sbt" / ".credentials")

 publishTo := Some("X Maven Repo" at "http://nexus/content/groups/common")

My Maven settings.xml

 <mirrors>
 <mirror>
  <id>x-repo</id>
  <name>X Maven repo</name>
      <url>http://nexus/content/groups/common</url>
  <mirrorOf>*</mirrorOf>
 </mirror>
 </mirrors>

 <servers>
     <server>
       <id>x-repo</id>
       <username>repouser</username>
       <password>password</password>
     </server>
   </servers>

I have followed instructions from official doc and various other posts, including StackOverflow such this one or mailing list such as this. None worked. I have tried enabling extra logging, but no further details are given.

I can manually deploy to maven using this command:

 mvn deploy:deploy-file -Durl=http://nexus/content/repositories/libs-snapshots -DrepositoryId=x-repo -DgroupId=com.app -DartifactId=app -Dpackaging=jar -Dversion=0.1-SNAPSHOT -Dfile=D:\app\target\scala-2.10\app_2.10-0.1.jar

Tried using the following publishTo, also without luck

publishTo <<= version { v: String =>
  val nexus = "http://nexus/" 
  if (v.trim.endsWith("SNAPSHOT"))
    Some("snapshots" at nexus + "content/repositories/libs-snapshots")
  else
    Some("releases" at nexus + "content/repositories/libs-releases")
  }

The commands run OK until they need to be authorized, at which point they fail.

The Realm in the credentials, does it correspond to the Server Repository ID in maven or the Name? Either or it doesn't work.

I've been trying to enable more logging for Ivy, but couldn't get more details.

set ivyLoggingLevel := UpdateLogging.Full

According to this, there should be further logging:

https://svn.apache.org/repos/asf/ant/ivy/core/tags/2.2.0/src/java/org/apache/ivy/util/url/IvyAuthenticator.java

I'm behind a internal proxy, so i need to set both HTTP user and HTTPS user and password. Perhaps it's here that it's getting blocked?

any suggestions how to increase the level of ivy logging?


Update

I've got something to work, by using sbt-aether-deploy plugin, which uses Maven infrastructure (wagon) to deploy.

Credentials are exactly the same. In fact, the realm didn't seem to matter.

following are the lines used:

    credentials += Credentials(Path.userHome / ".sbt" / ".credentials")

publishTo <<= version { v: String =>
  val nexus = "http://nexus/"
    if (v.trim.endsWith("SNAPSHOT"))
    Some("snapshots" at nexus + "content/repositories/libs-snapshots")
  else 
    Some("releases" at nexus + "content/repositories/libs-releases")
}

seq(aetherSettings: _*)

seq(aetherPublishSettings: _*)

Something is not right between the proxy, ivy and nexus.

I would still be interested in suggestions to use ivy.


Further update:

Using

curl -X POST http://nexusUser:nexusPassword@nexus/content/repositories/libs-snapshots -v

I was able to reach the server.

Same result specifying the proxy to use (it's configured to bypass for local networks, but some java processes like SBT seem to require the headers)

When nexusUser:nexusPassword were not specificied, i was getting the following header:

WWW-Authenticate: BASIC realm="Sonatype Nexus Repository Manager"

effectively that was the issue, the credentials required the name of the Realm to be that exact header, as opposed to other custom repository name like maven defines.

Many thanks!

回答1:

Ivy uses the realm of the WWW-Authenticate header, which will have to match byte-for-byte equal to the one configured in your credentials file.

sbt-aether-deploy uses the same header, but uses Aether as its deployment mechanism. Ivy does not.

The easiest way of figuring out the value of the WWW-Authenticate header is by using cURL.

curl -X POST http://nexus/content/repositories/libs-snapshots -v > /dev/null

cURL will prompt you for a user and pass.

-v will add verbosity so you will be able to see the headers of the request and response.



回答2:

I suspect that your credentials file path may be incorrect. Try changing this:

credentials += Credentials(Path.userHome / ".sbt" / ".credentials")

to that:

credentials += Credentials("c:/data/user/.sbt/.credentials")

or try directly to troubleshoot first:

credentials += Credentials("Sonatype Nexus Repository Manager", 
  "nexus.scala-tools.org", "admin", "admin123") 

If these don't work check that your credentials are valid.