Skip to content

Commit

Permalink
Add specs for the redirect URL creation
Browse files Browse the repository at this point in the history
  • Loading branch information
juretta committed Aug 14, 2012
1 parent 1de512c commit cac61ed
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 22 deletions.
Expand Up @@ -2,11 +2,7 @@ package play.api.libs.openid

import org.specs2.mutable.Specification
import org.specs2.mock._
import scala.io.Source
import org.jboss.netty.handler.codec.http.QueryStringDecoder
import java.net.{MalformedURLException, URL}
import util.control.Exception._
import collection.JavaConverters._
import java.net.URL
import play.api.http.HeaderNames
import play.api.http.Status._
import org.specs2.control.NoStackTraceFilter
Expand Down Expand Up @@ -270,11 +266,4 @@ object DiscoverySpec extends Specification with Mockito {
case Some(value) => params.get(key) must beSome(Seq(value))
case _ => params.get(key) must beNone
}

private def parseQueryString(url: String): Params = {
catching(classOf[MalformedURLException]) opt new URL(url) map {
url =>
new QueryStringDecoder(url.toURI.getRawQuery, false).getParameters.asScala.mapValues(_.asScala.toSeq).toMap
} getOrElse Map()
}
}
Expand Up @@ -15,17 +15,98 @@ object OpenIDSpec extends Specification with Mockito {
val identity = "http://example.com/openid?id=C123&id"
val defaultSigned = "op_endpoint,claimed_id,identity,return_to,response_nonce,assoc_handle"

// 9.1 Request parameters - http://openid.net/specs/openid-authentication-2_0.html#anchor27
def isValidOpenIDRequest(query:Params) = {
query.get("openid.mode") must beSome(Seq("checkid_setup"))
query.get("openid.ns") must beSome(Seq("http://specs.openid.net/auth/2.0"))
}

"OpenID" should {
"initiate discovery" in {
val ws = new WSMock
val ws = createMockWithValidOpDiscoveryAndVerification
val openId = new OpenIDClient(ws.url)
openId.redirectURL("http://example.com", "http://foo.bar.com/openid")
there was one(ws.request).get()
}

"generate a valid redirectUrl" in {
val ws = createMockWithValidOpDiscoveryAndVerification
val openId = new OpenIDClient(ws.url)
val redirectUrl = openId.redirectURL("http://example.com", "http://foo.bar.com/returnto").value.get

val query = parseQueryString(redirectUrl)

isValidOpenIDRequest(query)

query.get("openid.return_to") must beSome(Seq("http://foo.bar.com/returnto"))
query.get("openid.realm") must beNone
}

"generate a valid redirectUrl including the realm" in {
val ws = createMockWithValidOpDiscoveryAndVerification
val openId = new OpenIDClient(ws.url)
val redirectUrl = openId.redirectURL("http://example.com", "http://foo.bar.com/returnto", realm = Some("http://*.bar.com")).value.get

val query = parseQueryString(redirectUrl)

isValidOpenIDRequest(query)

query.get("openid.realm") must beSome(Seq("http://*.bar.com"))
}

"generate a valid redirectUrl with a proper required extended attributes request" in {
val ws = createMockWithValidOpDiscoveryAndVerification
val openId = new OpenIDClient(ws.url)
val redirectUrl = openId.redirectURL("http://example.com", "http://foo.bar.com/returnto",
axRequired = Seq("email" -> "http://schema.openid.net/contact/email")).value.get

val query = parseQueryString(redirectUrl)

isValidOpenIDRequest(query)

query.get("openid.ax.mode") must beSome(Seq("fetch_request"))
query.get("openid.ns.ax") must beSome(Seq("http://openid.net/srv/ax/1.0"))
query.get("openid.ax.required") must beSome(Seq("email"))
query.get("openid.ax.type.email") must beSome(Seq("http://schema.openid.net/contact/email"))
}

"generate a valid redirectUrl with a proper 'if_available' extended attributes request" in {
val ws = createMockWithValidOpDiscoveryAndVerification
val openId = new OpenIDClient(ws.url)
val redirectUrl = openId.redirectURL("http://example.com", "http://foo.bar.com/returnto",
axOptional = Seq("email" -> "http://schema.openid.net/contact/email")).value.get

val query = parseQueryString(redirectUrl)

isValidOpenIDRequest(query)

query.get("openid.ax.mode") must beSome(Seq("fetch_request"))
query.get("openid.ns.ax") must beSome(Seq("http://openid.net/srv/ax/1.0"))
query.get("openid.ax.if_available") must beSome(Seq("email"))
query.get("openid.ax.type.email") must beSome(Seq("http://schema.openid.net/contact/email"))
}

"generate a valid redirectUrl with a proper 'if_available' AND required extended attributes request" in {
val ws = createMockWithValidOpDiscoveryAndVerification
val openId = new OpenIDClient(ws.url)
val redirectUrl = openId.redirectURL("http://example.com", "http://foo.bar.com/returnto",
axRequired = Seq("first" -> "http://axschema.org/namePerson/first"),
axOptional = Seq("email" -> "http://schema.openid.net/contact/email")).value.get

val query = parseQueryString(redirectUrl)

isValidOpenIDRequest(query)

query.get("openid.ax.mode") must beSome(Seq("fetch_request"))
query.get("openid.ns.ax") must beSome(Seq("http://openid.net/srv/ax/1.0"))
query.get("openid.ax.required") must beSome(Seq("first"))
query.get("openid.ax.type.first") must beSome(Seq("http://axschema.org/namePerson/first"))
query.get("openid.ax.if_available") must beSome(Seq("email"))
query.get("openid.ax.type.email") must beSome(Seq("http://schema.openid.net/contact/email"))
}

"verify the response" in {
val ws = new WSMock

ws.response.header(HeaderNames.CONTENT_TYPE) returns Some("text/plain")
ws.response.body returns "is_valid:true\n" // http://openid.net/specs/openid-authentication-2_0.html#kvform

Expand Down Expand Up @@ -82,13 +163,7 @@ object OpenIDSpec extends Specification with Mockito {

// OpenID 1.1 compatibility - 14.2.1
"verify an OpenID 1.1 response that is missing the \"openid.op_endpoint\" parameter" in {
val ws = new WSMock

ws.response.status returns OK thenReturns OK
ws.response.header(HeaderNames.CONTENT_TYPE) returns Some("application/xrds+xml") thenReturns Some("text/plain")
ws.response.xml returns scala.xml.XML.loadString(readFixture("discovery/xrds/simple-op.xml"))
ws.response.body returns "is_valid:true\n" // http://openid.net/specs/openid-authentication-2_0.html#kvform

val ws = createMockWithValidOpDiscoveryAndVerification
val openId = new OpenIDClient(ws.url)

val responseQueryString = (openIdResponse - "openid.op_endpoint")
Expand All @@ -110,6 +185,15 @@ object OpenIDSpec extends Specification with Mockito {
}
}

def createMockWithValidOpDiscoveryAndVerification = {
val ws = new WSMock
ws.response.status returns OK thenReturns OK
ws.response.header(HeaderNames.CONTENT_TYPE) returns Some("application/xrds+xml") thenReturns Some("text/plain")
ws.response.xml returns scala.xml.XML.loadString(readFixture("discovery/xrds/simple-op.xml"))
ws.response.body returns "is_valid:true\n" // http://openid.net/specs/openid-authentication-2_0.html#kvform
ws
}

def setupMockRequest(queryString:Params = openIdResponse) = {
val request = mock[Request[_]]
request.queryString returns queryString
Expand Down
@@ -1,7 +1,10 @@
package play.api.libs

import java.net.URL
import io.Source
import org.jboss.netty.handler.codec.http.QueryStringDecoder
import java.net.{MalformedURLException, URL}
import util.control.Exception._
import collection.JavaConverters._
import play.api.libs.ws.WS.WSRequestHolder
import play.api.libs.ws.Response
import play.api.libs.concurrent.Promise
Expand All @@ -24,6 +27,12 @@ package object openid {

def readFixture(filePath: String) = Source.fromInputStream(this.getClass.getResourceAsStream(filePath)).mkString

def parseQueryString(url: String): Params = {
catching(classOf[MalformedURLException]) opt new URL(url) map {
url =>
new QueryStringDecoder(url.toURI.getRawQuery, false).getParameters.asScala.mapValues(_.asScala.toSeq).toMap
} getOrElse Map()
}

// See 10.1 - Positive Assertions
// http://openid.net/specs/openid-authentication-2_0.html#positive_assertions
Expand Down

0 comments on commit cac61ed

Please sign in to comment.