blob: 2c163bb06cfd64a45900a45f0c00c7541fa7cbb0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.gearpump.services.security.oauth2
import scala.collection.JavaConverters._
import scala.concurrent.Await
import scala.concurrent.duration._
import akka.actor.ActorSystem
import akka.http.scaladsl.model.HttpEntity.Strict
import akka.http.scaladsl.model.MediaTypes._
import akka.http.scaladsl.model.Uri.{Path, Query}
import akka.http.scaladsl.model._
import akka.http.scaladsl.testkit.ScalatestRouteTest
import com.typesafe.config.ConfigFactory
import org.scalatest.FlatSpec
import org.apache.gearpump.security.Authenticator
// NOTE: This cannot be removed!!!
import org.apache.gearpump.services.util.UpickleUtil._
import org.apache.gearpump.services.security.oauth2.impl.CloudFoundryUAAOAuth2Authenticator
class CloudFoundryUAAOAuth2AuthenticatorSpec extends FlatSpec with ScalatestRouteTest {
implicit val actorSystem: ActorSystem = system
private val server = new MockOAuth2Server(system, null)
server.start()
private val serverHost = s"http://127.0.0.1:${server.port}"
val configMap = Map(
"class" ->
"org.apache.gearpump.services.security.oauth2.impl.CloudFoundryUAAOAuth2Authenticator",
"callback" -> s"$serverHost/login/oauth2/cloudfoundryuaa/callback",
"clientid" -> "gearpump_test2",
"clientsecret" -> "gearpump_test2",
"default-userrole" -> "user",
"icon" -> "/icons/uaa.png",
"uaahost" -> serverHost,
"additional-authenticator-enabled" -> "false")
val configString = ConfigFactory.parseMap(configMap.asJava)
lazy val uaa = {
val uaa = new CloudFoundryUAAOAuth2Authenticator
uaa.init(configString, system.dispatcher)
uaa
}
it should "generate the correct authorization request" in {
val parameters = Uri(uaa.getAuthorizationUrl()).query().toMap
assert(parameters("response_type") == "code")
assert(parameters("client_id") == configMap("clientid"))
assert(parameters("redirect_uri") == configMap("callback"))
assert(parameters("scope") == "openid,cloud_controller.read")
}
it should "authenticate the authorization code and return the correct profile" in {
val code = Map("code" -> "QGGVeA")
val accessToken = "e2922002-0218-4513-a62d-1da2ba64ee4c"
val refreshToken = "eyJhbGciOiJSUzI1NiJ9.eyJqdGkiOiI2Nm"
val mail = "test@gearpump.apache.org"
def accessTokenEndpoint(request: HttpRequest): HttpResponse = {
assert(request.getHeader("Authorization").get.value() ==
"Basic Z2VhcnB1bXBfdGVzdDI6Z2VhcnB1bXBfdGVzdDI=")
assert(request.entity.contentType.mediaType.value == "application/x-www-form-urlencoded")
val body = request.entity.asInstanceOf[Strict].data.decodeString("UTF-8")
val form = Uri./.withQuery(Query(body)).query().toMap
assert(form("grant_type") == "authorization_code")
assert(form("code") == "QGGVeA")
assert(form("response_type") == "token")
assert(form("redirect_uri") == configMap("callback"))
val response =
s"""
|{
| "access_token": "$accessToken",
| "token_type": "bearer",
| "refresh_token": "$refreshToken",
| "expires_in": 43199,
| "scope": "openid",
| "jti": "e8739474-b2fa-42eb-a9ad-e065bf79d7e9"
|}
""".stripMargin
HttpResponse(entity = HttpEntity(ContentType(`application/json`), response))
}
def protectedResourceEndpoint(request: HttpRequest): HttpResponse = {
assert(request.getUri().query().get("access_token").get == accessToken)
val response =
s"""
|{
| "user_id": "e2922002-0218-4513-a62d-1da2ba64ee4c",
| "user_name": "user",
| "email": "$mail"
|}
""".stripMargin
HttpResponse(entity = HttpEntity(ContentType(`application/json`), response))
}
server.requestHandler = (request: HttpRequest) => {
if (request.uri.path.startsWith(Path("/oauth/token"))) {
accessTokenEndpoint(request)
} else if (request.uri.path.startsWith(Path("/userinfo"))) {
protectedResourceEndpoint(request)
} else {
fail("Unexpected access to " + request.uri.toString())
}
}
val userFuture = uaa.authenticate(code)
val user = Await.result(userFuture, 30.seconds)
assert(user.user == mail)
assert(user.permissionLevel == Authenticator.User.permissionLevel)
}
override def cleanUp(): Unit = {
server.stop()
uaa.close()
super.cleanUp()
}
}