OAuthSpec.scala 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. import com.weEat.controllers.UserController
  2. import play.api.test.Helpers._
  3. import play.api.test.FakeRequest
  4. import play.api.mvc.{Results,Headers}
  5. import play.api.libs.json.Json
  6. import org.scalatest.BeforeAndAfterAll
  7. import org.scalatestplus.play._
  8. import org.scalatestplus.play.guice.GuiceOneServerPerSuite
  9. import com.weEat.shared.models.{User,UserAuthorization}
  10. import java.util.Base64
  11. import org.bson.types.ObjectId
  12. import scala.concurrent.Future
  13. import javax.inject.Inject
  14. class OAuthSpec @Inject()(
  15. userController: UserController
  16. ) extends PlaySpec
  17. with BeforeAndAfterAll
  18. with Results
  19. with GuiceOneServerPerSuite {
  20. val email = "tuser@sample.org"
  21. val password = "password"
  22. val fname = "test"
  23. val lname = "user"
  24. val users = Seq(
  25. (User(new ObjectId(), "test", "user", "tuser@sample.org"), "password"),
  26. (User(new ObjectId(), "another", "user", "usert@sample.org"), "password")
  27. )
  28. implicit class CSRFWrapper[T](requ: FakeRequest[T]) {
  29. def withCSRFToken() = requ.withHeaders(
  30. requ.headers.add(("Csrf-Token", "nocheck"))
  31. )
  32. }
  33. def makeAuthHeader(username: String, password: String) =
  34. Headers(("Authorization" -> s"Basic ${new String(Base64.getEncoder.encode(s"$username:$password".getBytes))}"))
  35. def makeAuthHeader(auth: UserAuthorization) =
  36. Headers(("Authorization" -> s"${auth.tokenType} ${auth.accessToken}"))
  37. override def beforeAll() = {
  38. for ((User(_, fname, lname, email), password) <- users) {
  39. val Some(resp) = route(app, FakeRequest(PUT, "/v1/user/").withJsonBody(
  40. Json.parse(s"""|{
  41. | "fname": "$fname",
  42. | "lname": "$lname",
  43. | "email": "$email",
  44. | "password": "$password"
  45. |}""".stripMargin)
  46. ).withCSRFToken())
  47. status(resp) mustEqual OK
  48. }
  49. }
  50. override def afterAll() = {
  51. implicit val ec: scala.concurrent.ExecutionContext = scala.concurrent.ExecutionContext.global
  52. Future.sequence(Seq(
  53. userController.deleteUser(users(0)._1._id),
  54. )).map { (deletes) =>
  55. deletes must matchPattern {
  56. case Seq(_) =>
  57. }
  58. }
  59. // val Some(resp) = route(app, FakeRequest(DELETE, s"/v1/user/${users(0)._id}"))
  60. // status(resp) mustEqual OK
  61. // val Some(resp) = route(app, FakeRequest(DELETE, s"/v1/user/${users(1)._id}"))
  62. // status(resp) mustEqual OK
  63. }
  64. "the token endpoint" should {
  65. "reject an empty request" in {
  66. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  67. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  68. .withCSRFToken()
  69. )
  70. status(resp) mustEqual BAD_REQUEST
  71. headers(resp) must contain ("WWW-Authenticate" ->
  72. ("Bearer error=\"invalid_request\", "+
  73. "error_description=\"required parameter: grant_type\"")
  74. )
  75. }
  76. "reject an improperly formatted request" in {
  77. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  78. .withBody("""{"grant_type" "password"}""")
  79. .withHeaders(
  80. makeAuthHeader(email, password).add(("Content-Type", "application/json"))
  81. ).withCSRFToken()
  82. )
  83. status(resp) mustEqual BAD_REQUEST
  84. // Won't get an OAuth response header. Will fail before processing.
  85. }
  86. "reject a missing grant_type" in {
  87. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  88. .withJsonBody(Json.parse("{}"))
  89. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  90. .withCSRFToken()
  91. )
  92. status(resp) mustEqual BAD_REQUEST
  93. headers(resp) must contain ("WWW-Authenticate" ->
  94. ("Bearer error=\"invalid_request\", "+
  95. "error_description=\"required parameter: grant_type\"")
  96. )
  97. }
  98. }
  99. "the token endpoint for password grants" should {
  100. "accept a valid login" in {
  101. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  102. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  103. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  104. .withCSRFToken()
  105. )
  106. status(resp) mustEqual OK
  107. contentAsJson(resp).as[UserAuthorization] must matchPattern {
  108. case UserAuthorization(_, _, _, _, _) =>
  109. }
  110. }
  111. "issue unique access tokens for successive logins" in {
  112. val requ = FakeRequest(POST, "/authorize/")
  113. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  114. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  115. .withCSRFToken()
  116. val Some(resp1) = route(app, requ)
  117. val Some(resp2) = route(app, requ)
  118. status(resp2) mustEqual OK
  119. val resp1Auth = contentAsJson(resp1).as[UserAuthorization]
  120. val resp2Auth = contentAsJson(resp2).as[UserAuthorization]
  121. resp1Auth must matchPattern {
  122. case UserAuthorization(_, _, _, _, _) =>
  123. }
  124. resp2Auth must matchPattern {
  125. case UserAuthorization(_, _, _, _, _) =>
  126. }
  127. resp1Auth.accessToken mustNot equal(resp2Auth.accessToken)
  128. resp1Auth.refreshToken mustNot equal(resp2Auth.refreshToken)
  129. }
  130. "reject an unregistered user" in {
  131. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  132. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  133. .withHeaders(makeAuthHeader(
  134. "_"+users(0)._1.email,
  135. "_"+users(0)._2
  136. ))
  137. .withCSRFToken()
  138. )
  139. status(resp) mustEqual UNAUTHORIZED
  140. headers(resp) must contain ("WWW-Authenticate" ->
  141. ("Bearer error=\"invalid_client\", "+
  142. "error_description=\"Invalid client or client is not authorized\""))
  143. }
  144. "reject an incorrect password" in {
  145. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  146. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  147. .withHeaders(makeAuthHeader(users(0)._1.email, "_"+users(0)._2))
  148. .withCSRFToken()
  149. )
  150. status(resp) mustEqual UNAUTHORIZED
  151. headers(resp) must contain ("WWW-Authenticate" ->
  152. ("Bearer error=\"invalid_client\", "+
  153. "error_description=\"Invalid client or client is not authorized\"")
  154. )
  155. }
  156. "reject an incorrect username" in {
  157. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  158. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  159. .withHeaders(makeAuthHeader("_"+users(0)._1.email, users(0)._2))
  160. .withCSRFToken()
  161. )
  162. status(resp) mustEqual UNAUTHORIZED
  163. headers(resp) must contain ("WWW-Authenticate" ->
  164. ("Bearer error=\"invalid_client\", "+
  165. "error_description=\"Invalid client or client is not authorized\"")
  166. )
  167. }
  168. "reject an requests without Authorization headers" in {
  169. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  170. .withJsonBody(Json.parse(s"""{"grant_type": "password"}""")
  171. ).withCSRFToken())
  172. status(resp) mustEqual BAD_REQUEST
  173. headers(resp) must contain ("WWW-Authenticate" ->
  174. ("Bearer error=\"invalid_request\", "+
  175. "error_description=\"Client credential is not found\"")
  176. )
  177. }
  178. }
  179. "the token endpoint for refresh grants" should {
  180. "accept a given refresh token" in {
  181. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  182. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  183. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  184. .withCSRFToken()
  185. ).get).as[UserAuthorization]
  186. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  187. .withJsonBody(Json.parse(s"""|{
  188. | "grant_type": "refresh_token",
  189. | "client_id": "${users(0)._1.email}",
  190. | "refresh_token": "${auth.refreshToken}"
  191. |}""".stripMargin))
  192. .withCSRFToken()
  193. )
  194. status(resp) mustEqual OK
  195. val newAuth = contentAsJson(resp).as[UserAuthorization]
  196. newAuth must matchPattern {
  197. case UserAuthorization(_, _, _, _, _) =>
  198. }
  199. newAuth.accessToken mustNot equal(auth.accessToken)
  200. newAuth.refreshToken mustNot equal(auth.refreshToken)
  201. }
  202. "reject a given refresh token on the second attempt" in {
  203. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  204. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  205. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  206. .withCSRFToken()
  207. ).get).as[UserAuthorization]
  208. val Some(resp1) = route(app, FakeRequest(POST, "/authorize/")
  209. .withJsonBody(Json.parse(s"""|{
  210. | "grant_type": "refresh_token",
  211. | "client_id": "${users(0)._1.email}",
  212. | "refresh_token": "${auth.refreshToken}"
  213. |}""".stripMargin))
  214. .withCSRFToken()
  215. )
  216. status(resp1) mustEqual OK
  217. contentAsJson(resp1).as[UserAuthorization] must matchPattern {
  218. case UserAuthorization(_, _, _, _, _) =>
  219. }
  220. val Some(resp2) = route(app, FakeRequest(POST, "/authorize/")
  221. .withJsonBody(Json.parse(s"""|{
  222. | "grant_type": "refresh_token",
  223. | "client_id": "${users(0)._1.email}",
  224. | "refresh_token": "${auth.refreshToken}"
  225. |}""".stripMargin))
  226. .withCSRFToken()
  227. )
  228. status(resp2) mustEqual UNAUTHORIZED
  229. headers(resp2) must contain ("WWW-Authenticate" ->
  230. ("Bearer error=\"invalid_client\", "+
  231. "error_description=\"Invalid client or client is not authorized\"")
  232. )
  233. }
  234. "reject a revoked refresh token" in {
  235. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  236. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  237. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  238. .withCSRFToken()
  239. ).get).as[UserAuthorization]
  240. val Some(resp1) = route(app, FakeRequest(DELETE, "/authorize/")
  241. .withJsonBody(Json.parse(s"""|{
  242. | "grant_type": "refresh_token",
  243. | "client_id": "${users(0)._1.email}",
  244. | "refresh_token": "${auth.refreshToken}"
  245. |}""".stripMargin))
  246. .withHeaders(makeAuthHeader(auth))
  247. .withCSRFToken()
  248. )
  249. status(resp1) mustEqual OK
  250. val Some(resp2) = route(app, FakeRequest(POST, "/authorize/")
  251. .withJsonBody(Json.parse(s"""|{
  252. | "grant_type": "refresh_token",
  253. | "client_id": "${users(0)._1.email}",
  254. | "refresh_token": "${auth.refreshToken}"
  255. |}""".stripMargin))
  256. .withCSRFToken()
  257. )
  258. status(resp2) mustEqual UNAUTHORIZED
  259. headers(resp2) must contain ("WWW-Authenticate" ->
  260. ("Bearer error=\"invalid_client\", "+
  261. "error_description=\"Invalid client or client is not authorized\"")
  262. )
  263. }
  264. "reject a given refresh token with an incorrect username" in {
  265. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  266. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  267. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  268. .withCSRFToken()
  269. ).get).as[UserAuthorization]
  270. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  271. .withJsonBody(Json.parse(s"""|{
  272. | "grant_type": "refresh_token",
  273. | "client_id": "_${users(0)._1.email}",
  274. | "refresh_token": "${auth.refreshToken}"
  275. |}""".stripMargin))
  276. .withCSRFToken()
  277. )
  278. status(resp) mustEqual UNAUTHORIZED
  279. headers(resp) must contain ("WWW-Authenticate" ->
  280. ("Bearer error=\"invalid_client\", "+
  281. "error_description=\"Invalid client or client is not authorized\"")
  282. )
  283. }
  284. "reject an unprovided refresh token" in {
  285. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  286. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  287. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  288. .withCSRFToken()
  289. ).get).as[UserAuthorization]
  290. val fakeToken = s"${auth.refreshToken.charAt(0)+1}${auth.refreshToken.substring(1)}";
  291. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  292. .withJsonBody(Json.parse(s"""|{
  293. | "grant_type": "refresh_token",
  294. | "client_id": "${users(0)._1.email}",
  295. | "refresh_token": "$fakeToken"
  296. |}""".stripMargin))
  297. .withCSRFToken()
  298. )
  299. status(resp) mustEqual UNAUTHORIZED
  300. headers(resp) must contain ("WWW-Authenticate" ->
  301. ("Bearer error=\"invalid_client\", "+
  302. "error_description=\"Invalid client or client is not authorized\"")
  303. )
  304. }
  305. }
  306. "the secured endpoint" should {
  307. "accept an authorized request" in {
  308. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  309. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  310. .withHeaders(makeAuthHeader(email, password))
  311. .withCSRFToken()
  312. ).get).as[UserAuthorization]
  313. val Some(resp) = route(app, FakeRequest(GET, "/v1/user/self/name/")
  314. .withHeaders(makeAuthHeader(auth))
  315. .withCSRFToken()
  316. )
  317. status(resp) mustEqual OK
  318. contentAsString(resp) must
  319. equal(s"${users(0)._1.fname} ${users(0)._1.lname}")
  320. }
  321. "reject an unauthorized request" in {
  322. val Some(resp) = route(app, FakeRequest(GET, "/v1/user/self/name/")
  323. .withCSRFToken()
  324. )
  325. status(resp) mustEqual BAD_REQUEST
  326. headers(resp) must contain ("WWW-Authenticate" ->
  327. ("Bearer error=\"invalid_request\", "+
  328. "error_description=\"Access token is not found\"")
  329. )
  330. }
  331. "reject an forged authorized request" in {
  332. val fakeToken = "7pKNy790TV5lKVjQw3k/pwJmMS8XBhHaLTVaI6ftd5M="
  333. val Some(resp) = route(app, FakeRequest(GET, "/v1/user/self/name/")
  334. .withHeaders(("Authorization" -> s"Bearer $fakeToken"))
  335. .withCSRFToken()
  336. )
  337. status(resp) mustEqual UNAUTHORIZED
  338. headers(resp) must contain ("WWW-Authenticate" ->
  339. ("Bearer error=\"invalid_token\", "+
  340. "error_description=\"The access token is not found\"")
  341. )
  342. }
  343. "reject a refreshed access token" in {
  344. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  345. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  346. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  347. .withCSRFToken()
  348. ).get).as[UserAuthorization]
  349. val Some(resp1) = route(app, FakeRequest(POST, "/authorize/")
  350. .withJsonBody(Json.parse(s"""|{
  351. | "grant_type": "refresh_token",
  352. | "client_id": "${users(0)._1.email}",
  353. | "refresh_token": "${auth.refreshToken}"
  354. |}""".stripMargin))
  355. .withCSRFToken()
  356. )
  357. status(resp1) mustEqual OK
  358. val Some(resp2) = route(app, FakeRequest(GET, "/v1/user/self/name/")
  359. .withHeaders(makeAuthHeader(auth))
  360. .withCSRFToken()
  361. )
  362. status(resp2) mustEqual UNAUTHORIZED
  363. headers(resp2) must contain ("WWW-Authenticate" ->
  364. ("Bearer error=\"invalid_token\", "+
  365. "error_description=\"The access token is invalid\"")
  366. )
  367. }
  368. "reject a revoked access token" in {
  369. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  370. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  371. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  372. .withCSRFToken()
  373. ).get).as[UserAuthorization]
  374. val Some(resp1) = route(app, FakeRequest(DELETE, "/authorize/")
  375. .withJsonBody(Json.parse(s"""|{
  376. | "grant_type": "refresh_token",
  377. | "client_id": "${users(0)._1.email}",
  378. | "refresh_token": "${auth.refreshToken}"
  379. |}""".stripMargin))
  380. .withHeaders(makeAuthHeader(auth))
  381. .withCSRFToken()
  382. )
  383. status(resp1) mustEqual OK
  384. val Some(resp2) = route(app, FakeRequest(GET, "/v1/user/self/name/")
  385. .withHeaders(makeAuthHeader(auth))
  386. .withCSRFToken()
  387. )
  388. status(resp2) mustEqual UNAUTHORIZED
  389. headers(resp2) must contain ("WWW-Authenticate" ->
  390. ("Bearer error=\"invalid_token\", "+
  391. "error_description=\"The access token is invalid\"")
  392. )
  393. }
  394. /*
  395. "reject an expired access token" taggedAs(Slow) in {
  396. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  397. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  398. .withHeaders(makeAuthHeader(email, password))
  399. ).get).as[UserAuthorization]
  400. Thread.sleep((1 hour).toMillis)
  401. val Some(resp) = route(app, FakeRequest(GET, "/v1/user/self/name/")
  402. .withHeaders(makeAuthHeader(auth)))
  403. status(resp) mustEqual UNAUTHORIZED
  404. headers(resp) must contain ("WWW-Authenticate" ->
  405. ("Bearer error=\"invalid_token\", "+
  406. "error_description=\"The access token is invalid\"")
  407. )
  408. }
  409. */
  410. }
  411. "the token endpoint for revokation requests" should {
  412. "accept a valid request" in {
  413. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  414. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  415. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  416. .withCSRFToken()
  417. ).get).as[UserAuthorization]
  418. val Some(resp) = route(app, FakeRequest(DELETE, "/authorize/")
  419. .withJsonBody(Json.parse(s"""|{
  420. | "grant_type": "refresh_token",
  421. | "client_id": "${users(0)._1.email}",
  422. | "refresh_token": "${auth.refreshToken}"
  423. |}""".stripMargin))
  424. .withHeaders(makeAuthHeader(auth))
  425. .withCSRFToken()
  426. )
  427. status(resp) mustEqual OK
  428. contentAsString(resp) mustEqual("")
  429. }
  430. "reject a request with an invalid authorization header" in {
  431. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  432. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  433. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  434. .withCSRFToken()
  435. ).get).as[UserAuthorization]
  436. val fakeToken = s"${auth.accessToken.charAt(0)+1}${auth.accessToken.substring(1)}";
  437. val Some(resp) = route(app, FakeRequest(DELETE, "/authorize/")
  438. .withJsonBody(Json.parse(s"""|{
  439. | "grant_type": "refresh_token",
  440. | "client_id": "${users(0)._1.email}",
  441. | "refresh_token": "${auth.refreshToken}"
  442. |}""".stripMargin))
  443. .withHeaders("Authorization" -> s"Bearer $fakeToken")
  444. .withCSRFToken()
  445. )
  446. status(resp) mustEqual UNAUTHORIZED
  447. headers(resp) must contain ("WWW-Authenticate" ->
  448. ("Bearer error=\"invalid_token\", "+
  449. "error_description=\"The access token is not found\"")
  450. )
  451. }
  452. "reject a request without an authorization header" in {
  453. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  454. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  455. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  456. .withCSRFToken()
  457. ).get).as[UserAuthorization]
  458. val Some(resp) = route(app, FakeRequest(DELETE, "/authorize/")
  459. .withJsonBody(Json.parse(s"""|{
  460. | "grant_type": "refresh_token",
  461. | "client_id": "${users(0)._1.email}",
  462. | "refresh_token": "${auth.refreshToken}"
  463. |}""".stripMargin))
  464. .withCSRFToken()
  465. )
  466. status(resp) mustEqual BAD_REQUEST
  467. headers(resp) must contain ("WWW-Authenticate" ->
  468. ("Bearer error=\"invalid_request\", "+
  469. "error_description=\"Access token is not found\"")
  470. )
  471. }
  472. "reject a request with an unissued refresh token" in {
  473. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  474. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  475. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  476. .withCSRFToken()
  477. ).get).as[UserAuthorization]
  478. val fakeToken = s"${auth.refreshToken.charAt(0)+1}${auth.refreshToken.substring(1)}";
  479. val Some(resp) = route(app, FakeRequest(DELETE, "/authorize/")
  480. .withJsonBody(Json.parse(s"""|{
  481. | "grant_type": "refresh_token",
  482. | "client_id": "${users(0)._1.email}",
  483. | "refresh_token": "${fakeToken}"
  484. |}""".stripMargin))
  485. .withHeaders(makeAuthHeader(auth))
  486. .withCSRFToken()
  487. )
  488. status(resp) mustEqual UNAUTHORIZED
  489. headers(resp) must contain ("WWW-Authenticate" ->
  490. ("Bearer error=\"invalid_token\", "+
  491. "error_description=\"The access token is invalid\"")
  492. )
  493. }
  494. "reject a request with an incorrect username" in {
  495. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  496. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  497. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  498. .withCSRFToken()
  499. ).get).as[UserAuthorization]
  500. val Some(resp) = route(app, FakeRequest(DELETE, "/authorize/")
  501. .withJsonBody(Json.parse(s"""|{
  502. | "grant_type": "refresh_token",
  503. | "client_id": "_${users(0)._1.email}",
  504. | "refresh_token": "${auth.refreshToken}"
  505. |}""".stripMargin))
  506. .withHeaders(makeAuthHeader(auth))
  507. .withCSRFToken()
  508. )
  509. status(resp) mustEqual UNAUTHORIZED
  510. headers(resp) must contain ("WWW-Authenticate" ->
  511. ("Bearer error=\"invalid_client\", "+
  512. "error_description=\"Invalid client or client is not authorized\"")
  513. )
  514. }
  515. }
  516. }