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:
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!
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.