diff --git a/build.sbt b/build.sbt
index d034c11f14dcc210201691ec9b216d179ef55282..811926eed42611f21484fcb3c3895c6fbcf8ac34 100644
--- a/build.sbt
+++ b/build.sbt
@@ -55,12 +55,15 @@ lazy val ItTest = config("it") extend(Test)
 
 testOptions in ItTest := Seq(Tests.Argument("-oDF"))
 
-def ghProject(repo: String, version: String) = RootProject(uri(s"${repo}#${version}"))
+def ghProject(repo: String, version: String) = RootProject(uri(s"git://$repo#$version"))
 
-lazy val bonsai      = ghProject("git://github.com/colder/bonsai.git",     "10eaaee4ea0ff6567f4f866922cb871bae2da0ac")
-lazy val scalaSmtlib = ghProject("git://github.com/regb/scala-smtlib.git", "850580ae86e299a1baa0eaef9e24eed905fefe58")
+def svnProject(repo: String, version: String, user: String, pass: String) =
+  RootProject(uri(s"svn+credentials://$repo#username=$user&password=$pass&$version"))
 
-lazy val princess    = ghProject("svn://hal4.it.uu.se/princess/interpolation/trunk", "2703")
+lazy val bonsai      = ghProject("github.com/colder/bonsai.git",     "10eaaee4ea0ff6567f4f866922cb871bae2da0ac")
+lazy val scalaSmtlib = ghProject("github.com/regb/scala-smtlib.git", "850580ae86e299a1baa0eaef9e24eed905fefe58")
+
+lazy val princess    = svnProject("hal4.it.uu.se/princess/interpolation/trunk", "2703", "anonymous", "anonymous")
 
 // XXX @nv: complex hack to make sure we don't have a name clash between
 //          princess' smtlib parser and the scala-smtlib one.
diff --git a/project/Build.scala b/project/Build.scala
new file mode 100644
index 0000000000000000000000000000000000000000..82e21d7515ddaef206006c8db099081e1bfb565b
--- /dev/null
+++ b/project/Build.scala
@@ -0,0 +1,51 @@
+import sbt._
+import Keys._
+import RichURI._
+
+object InoxBuild extends Build {
+
+  override def buildLoaders = BuildLoader.resolve(svnResolver) :: Nil
+
+  // Define the custom resolver which handles the 'svn' scheme with a username/password pair.
+  def svnResolver(info: BuildLoader.ResolveInfo): Option[() => File] =
+    if (info.uri.getScheme != "svn+credentials") None else {
+      val uri = info.uri.withoutMarkerScheme
+      val localCopy = Resolvers.uniqueSubdirectoryFor(uri, in = info.staging)
+      val from = uri.copy(scheme = "svn").withoutFragment.toASCIIString
+      val to = localCopy.getAbsolutePath
+
+      sealed abstract class SVNInfo
+      case class Username(user: String) extends SVNInfo
+      case class Password(pass: String) extends SVNInfo
+      case class Tag(tag: String) extends SVNInfo
+
+      val fragment = uri.getFragment
+      val splits = fragment.split("&").toSeq
+      val infos = splits.map(s => s.split("=").toSeq match {
+        case Seq("username", user) => Username(user)
+        case Seq("password", pass) => Password(pass)
+        case Seq(tag) => Tag(tag)
+        case _ => sys.error("Unexpected fragment: " + fragment)
+      })
+
+      val username = infos.collect { case Username(user) => user } match {
+        case Seq(user) => user
+        case _ => sys.error("Invalid username specification for svn+credentials scheme.")
+      }
+
+      val password = infos.collect { case Password(pass) => pass } match {
+        case Seq(pass) => pass
+        case _ => sys.error("Invalid password specification for svn+credentials scheme.")
+      }
+
+      infos.collect { case Tag(tag) => tag } match {
+        case Seq(tag) => Some(() => Resolvers.creates(localCopy) {
+          Resolvers.run("svn", "checkout", "-q", "-r", tag, "--username", username, "--password", password, from, to)
+        })
+        case Seq() => Some(() => Resolvers.creates(localCopy) {
+          Resolvers.run("svn", "checkout", "-q", "--username", username, "--password", password, from, to)
+        })
+        case _ => sys.error("Invalid tag specification for svn+credentials scheme.")
+      }
+    }
+}