Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support HTTP proxy (username, password) authentication #100

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions requests/src/requests/Model.scala
Original file line number Diff line number Diff line change
Expand Up @@ -237,22 +237,22 @@ case class StreamHeaders(url: String,
* auth and Proxy auth are supported
*/
trait RequestAuth{
def header: Option[String]
def credentials: Option[String]
}

object RequestAuth{
object Empty extends RequestAuth{
def header = None
def credentials = None
}
implicit def implicitBasic(x: (String, String)): Basic = new Basic(x._1, x._2)
class Basic(username: String, password: String) extends RequestAuth{
def header = Some("Basic " + java.util.Base64.getEncoder.encodeToString((username + ":" + password).getBytes()))
def credentials = Some("Basic " + java.util.Base64.getEncoder.encodeToString((username + ":" + password).getBytes()))
}
case class Proxy(username: String, password: String) extends RequestAuth{
def header = Some("Proxy-Authorization " + java.util.Base64.getEncoder.encodeToString((username + ":" + password).getBytes()))
def credentials = Some("Basic " + java.util.Base64.getEncoder.encodeToString((username + ":" + password).getBytes()))
}
case class Bearer(token: String) extends RequestAuth {
def header = Some(s"Bearer $token")
def credentials = Some(s"Bearer $token")
}
}

Expand Down
12 changes: 11 additions & 1 deletion requests/src/requests/Requester.scala
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,17 @@ case class Requester(verb: String,
for((k, v) <- compress.headers) connection.setRequestProperty(k, v)

connection.setReadTimeout(readTimeout)
auth.header.foreach(connection.setRequestProperty("Authorization", _))

auth match {
case basic: RequestAuth.Basic =>
connection.setRequestProperty("Authorization", basic.credentials.get)
case bearer: RequestAuth.Bearer =>
connection.setRequestProperty("Authorization", bearer.credentials.get)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 236 and 238 are doing the same thing, maybe we can use case Foo | Bar to handle them both together in the same case.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've decided to tweak my implementation. Would appreciate any feedback you have on the latest round of changes :)

case proxy: RequestAuth.Proxy =>
connection.setRequestProperty("Proxy-Authorization", proxy.credentials.get)
case RequestAuth.Empty =>
}

connection.setConnectTimeout(connectTimeout)
connection.setUseCaches(false)
connection.setDoOutput(true)
Expand Down
39 changes: 39 additions & 0 deletions requests/test/src/requests/RequestTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,45 @@ object RequestTests extends TestSuite{
}
}
}
test("auth"){
test("basicAuth"){
val (username, password) = ("foo", "bar")
val rawCreds = s"$username:$password"
val encodedCreds = java.util.Base64.getEncoder.encodeToString(rawCreds.getBytes())
val auth = new RequestAuth.Basic(username, password)

val res = requests.get("https://httpbin.org/headers", auth=auth).text()
val hs = read(res)("headers").obj

assert(hs("Authorization").str == s"Basic $encodedCreds")
}
test("bearerAuth"){
val token = "foobar"
val auth = new RequestAuth.Bearer(token)

val res = requests.get("https://httpbin.org/headers", auth=auth).text()
val hs = read(res)("headers").obj

assert(hs("Authorization").str == s"Bearer $token")
}
test("proxyAuth"){
// @TODO Need a service that echos the Proxy-Authorization header back.
//
// From RFC: "Unlike Authorization, the Proxy-Authorization header field
// applies only to the next inbound proxy that demanded authentication
// using the Proxy-Authenticate field." [0]
//
// [0] https://tools.ietf.org/html/rfc7235#section-4.4
//
// val (username, password) = ("foo", "bar")
// val rawCreds = s"$username:$password"
// val encodedCreds = java.util.Base64.getEncoder.encodeToString(rawCreds.getBytes())
// val auth = new RequestAuth.Proxy(username, password)
// val res = requests.get("http://localhost:8881", auth=auth).text()
// val hs = read(res)("headers").obj
// assert(hs("Proxy-Authorization").str == s"Basic $encodedCreds")
}
}
test("clientCertificate"){
val base = "./requests/test/resources"
val url = "https://client.badssl.com"
Expand Down