Applying pac4j-play's Example

1,243 views
Skip to first unread message

Kevin Meredith

unread,
Nov 26, 2017, 2:12:49 PM11/26/17
to Pac4j users mailing list
Given the following JKS and Metadata XML:

$ls -lrot conf
total 64
-rw-r--r--@ 1 kevinmeredith  6860 Nov 24 11:48 MetaData.xml
-rw-r--r--  1 kevinmeredith  2992 Nov 26 13:52 clientkeystore.jks
... omitted the rest


and the following Scala code, copied mainly from the helpful https://github.com/pac4j/play-pac4j's sample project:

controllers/HomeController.scala

@Singleton
class HomeController @Inject()(cc: ControllerComponents, val config: Config, val playSessionStore: PlaySessionStore)
  extends AbstractController(cc) with Security[CommonProfile] {

  /**
   * Create an Action to render an HTML page.
   *
   * The configuration in the `routes` file means that this method
   * will be called when the application receives a `GET` request with
   * a path of `/`.
   */
  def index() = Secure("SAML2Client") { profiles =>
    Action { implicit request: Request[AnyContent] =>
      Ok(views.html.index("protected index"))
    }
  }
}

modules/SecurityModule.scala

class SecurityModule(environment: Environment, configuration: Configuration) extends AbstractModule {

  override def configure(): Unit = {
    val cfg = new SAML2ClientConfiguration("resource:clientkeystore.jks", "changeit", "changeit", "resource:MetaData.xml")
    cfg.setMaximumAuthenticationLifetime(3600)
    val saml2Client = new SAML2Client(cfg)

    val baseUrl: String = "http://localhost:9000"

    val clients = new Clients(baseUrl + "/index", saml2Client)

    val config = new Config(clients)
    config.addAuthorizer("user", new RequireAnyRoleAuthorizer[Nothing]("USER"))
    config.setHttpActionAdapter(new DefaultHttpActionAdapter())
    bind(classOf[Config]).toInstance(config)

    bind(classOf[PlaySessionStore]).to(classOf[PlayCacheSessionStore])

    val callbackController = new CallbackController()
    callbackController.setDefaultUrl("/?defaulturlafterlogout")
    callbackController.setMultiProfile(true)
    bind(classOf[CallbackController]).toInstance(callbackController)

    val logoutController = new LogoutController()
    logoutController.setDefaultUrl("/logout")
    bind(classOf[LogoutController]).toInstance(logoutController)
  }
}

conf/application.conf

play.http.filters = "filters.Filters"

play.modules.enabled += "modules.SecurityModule"

pac4j.security {
  rules = [
    {"/index" = {
      authorizers = "_authenticated_"
      clients = "SAML2Client"
    }}
    {"/public" = {
      authorizers = "_anonymous_"
    }}
  ]
}

conf/routes

GET     /index                      controllers.HomeController.index


When I run the app via `sbt run`, I attempted to access http://localhost:9000/index, i.e. the SAML-protected route, in my browser.

I got re-directed to: https://app.company.com/VendorAuth/

Note that, at this point in time, the play app logs:

> o.p.p.f.SecurityFilter - Authentication failed for /index with clients SAML2Client and authorizers null. Authentication response code 200.

Then, I input my username without a password.

Consequently, my browser re-directed me to: https://app.company.com/VendorAuth/Authorized/SAML20IdPInit.aspx/debug=true.

However, the page has no content and keeps re-loading.

Can someone please advise me if I'm using pac4j-play incorrectly? It appeared that the re-direct worked, i..e. given the 'Authorized' in the URL, however, I
don't understand why the page keeps re-loading.

Thanks!



Jérôme LELEU

unread,
Nov 27, 2017, 2:30:32 AM11/27/17
to Kevin Meredith, Pac4j users mailing list
Hi,

Did you define the callback endpoint? I don't see it in the routes file.
Thanks.
Best regards,
Jérôme


--
You received this message because you are subscribed to the Google Groups "Pac4j users mailing list" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pac4j-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Kevin Meredith

unread,
Dec 5, 2017, 1:36:06 PM12/5/17
to Pac4j users mailing list
 Hi Jérôme -

I forgot to add it - thank you. Could you please explain to me what the purpose of the call-back URL is?

Regardless of this change, when accessing /index on my app, I get re-directed to the Identity Provider's login page. Before the re-direct, I see the following in the sbt run output:

[info] o.p.p.f.SecurityFilter - Authentication failed for /index with clients SAML2Client and authorizers null. Authentication response code 200.

After entering my username and password, I get re-directed to the Identity Provider-defined URL. Upon accessing /index again, i.e. in the same browser's tab, I get re-directed to the IdP's login again.

I had expected that, after logging in, I would not need to log in again for 1 hour given the following highlighted line:

private val provideSaml2Client: SAML2Client = {

val cfg = new SAML2ClientConfiguration("resource:clientkeystore.jks", "changeit", "changeit", "resource:MetaData.xml")
cfg.setMaximumAuthenticationLifetime(3600)
  new SAML2Client(cfg)
}

Could you please advise me?

Thanks!
Kevin
To unsubscribe from this group and stop receiving emails from it, send an email to pac4j-users...@googlegroups.com.

Jérôme LELEU

unread,
Dec 6, 2017, 11:12:44 AM12/6/17
to Kevin Meredith, Pac4j users mailing list
Hi,

The flow is simple: you try to access a /protected URL, you are redirected to an external identity server, then back to your application (after a successful login) on the /callback URL to finish the login process, and finally to the originally request URL: /protected.

Don't use /index as the callback URL. The /callback URL must NOT be protected to allow the login process to be completed.

Thanks.
Best regards,
Jérôme


To unsubscribe from this group and stop receiving emails from it, send an email to pac4j-users+unsubscribe@googlegroups.com.

Kevin Meredith

unread,
Dec 9, 2017, 7:47:35 PM12/9/17
to Pac4j users mailing list
Thank you, Jérôme.

I added the following to my conf/routes:

GET    /callback    @org.pac4j.play.CallbackController.callback()

Then, after navigating to /callback (during the SAML re-direct), I got an "Action Not Found" (HTTP-404) error from Play for the "POST /callback" route after logging into my Identity Provider.

Unsure of how to proceed, I modified the above route entry's method from GET to POST.

Finally, I re-ran the authentication chain by navigating to http://localhost:9000/index. But I got the following error:

[info] o.p.p.f.SecurityFilter - Authentication failed for /index with clients SAML2Client and authorizers null. Authentication response code 200.
[debug] o.p.p.f.SecurityFilter - No authentication needed for /callback
[debug] o.p.c.e.DefaultCallbackLogic - === CALLBACK ===
[error] application -

! @7698nb4bc - Internal server error, for (POST) [/callback] ->
 
play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[CompletionException: org.pac4j.core.exception.TechnicalException: name cannot be blank]]
    at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:255)
    at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:182)
    at play.core.server.AkkaHttpServer$$anonfun$$nestedInanonfun$executeHandler$1$1.applyOrElse(AkkaHttpServer.scala:251)
    at play.core.server.AkkaHttpServer$$anonfun$$nestedInanonfun$executeHandler$1$1.applyOrElse(AkkaHttpServer.scala:250)
    at scala.concurrent.Future.$anonfun$recoverWith$1(Future.scala:414)
    at scala.concurrent.impl.Promise.$anonfun$transformWith$1(Promise.scala:37)
    at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60)
    at play.api.libs.streams.Execution$trampoline$.execute(Execution.scala:70)
    at scala.concurrent.impl.CallbackRunnable.executeWithValue(Promise.scala:68)
    at scala.concurrent.impl.Promise$DefaultPromise.$anonfun$tryComplete$1(Promise.scala:284)
Caused by: java.util.concurrent.CompletionException: org.pac4j.core.exception.TechnicalException: name cannot be blank
    at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273)
    at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280)
    at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1592)
    at play.core.j.HttpExecutionContext$$anon$2.run(HttpExecutionContext.scala:56)
    at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:40)
    at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(ForkJoinExecutorConfigurator.scala:43)
    at akka.dispatch.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
    at akka.dispatch.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
    at akka.dispatch.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
    at akka.dispatch.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
Caused by: org.pac4j.core.exception.TechnicalException: name cannot be blank
    at org.pac4j.core.util.CommonHelper.assertTrue(CommonHelper.java:109)
    at org.pac4j.core.util.CommonHelper.assertNotBlank(CommonHelper.java:121)
    at org.pac4j.core.util.CommonHelper.assertNotBlank(CommonHelper.java:131)
    at org.pac4j.core.client.Clients.findClient(Clients.java:145)
    at org.pac4j.core.engine.DefaultCallbackLogic.perform(DefaultCallbackLogic.java:72)
    at org.pac4j.play.CallbackController.lambda$callback$0(CallbackController.java:50)
    at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
    at play.core.j.HttpExecutionContext$$anon$2.run(HttpExecutionContext.scala:56)
    at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:40)
    at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(ForkJoinExecutorConfigurator.scala:43)


Could you please advise me on what this means? Also, how can I address it?

Thanks!

Kevin Meredith

unread,
Dec 9, 2017, 8:57:00 PM12/9/17
to Pac4j users mailing list

Jérôme LELEU

unread,
Dec 11, 2017, 5:11:54 AM12/11/17
to Kevin Meredith, Pac4j users mailing list
Hi,

By using the demo (https://github.com/pac4j/play-pac4j-java-demo or https://github.com/pac4j/play-pac4j-scala-demo), you will save time: the /callback is defined both for GET and POST depending on the authentication mechanism.

Regarding your error, the client_name parameter is missing on the callback URL. When calling the identity provider, the provided callback URL should have this parameter.

Thanks.
Best regards,
Jérôme


--

Kevin Meredith

unread,
Dec 11, 2017, 12:50:43 PM12/11/17
to Jérôme LELEU, Pac4j users mailing list
Thank you for pointing me to that demo, Jérôme. I will be sure to take a look at it before posting another question in this or another thread!

With respect to:


> Regarding your error, the client_name parameter is missing on the callback URL. When calling the identity provider, the provided callback URL should have this parameter.

I don't entirely understand the "client_name parameter is missing on the callback URL" sentence.

Should the HTTP POST request specify this parameter? If so, how?

Or, must I, the application developer of the Service Provider, explicitly define the client_name parameter in SecurityModule.scala or elsewhere? Or, must the Identity Provider specify this value?

Could you please say more to help me to understand? It's not clear to me whether the Service Provider or Identity Provider must provide this `client_name` parameter, as well as how it must be provided.

Thanks!
Kevin

Jérôme LELEU

unread,
Dec 12, 2017, 2:57:47 AM12/12/17
to Kevin Meredith, Pac4j users mailing list
Hi,

When properly configured, the client_name parameter is added at the end of each callback URL of each client. This is what happens in the demo.

In fact, under the hood, the Clients class is initialized the first time the DefaultSecutiryLogic is called and this is where callback URLs are properly prepared.

Thanks.
Best regards,
Jérôme

Kevin Meredith

unread,
Dec 12, 2017, 9:42:20 PM12/12/17
to Pac4j users mailing list
Hi -

When you say properly configured, I'm guessing that you're referring to the Play App using your play-pac4j library (thank you for writing it)?

I modified my test Play app per the 'play-pac4j-scala-demo' repo. It consists of the below code. Could you please take a look to see if something catches your eye as wrong?

conf/routes

GET     /index                      controllers.HomeController.index
GET /public controllers.HomeController.public

# https://github.com/pac4j/play-pac4j#4-define-the-callback-endpoint-only-for-indirect-clients-callbackcontroller
POST /callback @org.pac4j.play.CallbackController.callback()

modules/SecurityModule.scala

package modules

import com.google.inject.{AbstractModule, Provides}
import controllers.CustomAuthorizer
import org.pac4j.core.client.Clients
import org.pac4j.play.http.DefaultHttpActionAdapter
import org.pac4j.play.{CallbackController, LogoutController}
import org.pac4j.saml.client.SAML2ClientConfiguration
import play.api.{Configuration, Environment}
import org.pac4j.play.store.{PlayCacheSessionStore, PlaySessionStore}
import org.pac4j.core.authorization.authorizer.RequireAnyRoleAuthorizer
import org.pac4j.core.config.Config
import org.pac4j.saml.client.SAML2Client


class SecurityModule(environment: Environment, configuration: Configuration) extends AbstractModule {

  val baseUrl: String = "http://localhost:9000"

  @Provides
def provideSaml2Client: SAML2Client = {

val cfg = new SAML2ClientConfiguration("resource:clientkeystore.jks", "changeit", "changeit", "resource:MetaData.xml")
cfg.setMaximumAuthenticationLifetime(3600)
new SAML2Client(cfg)
}


  override def configure(): Unit = {

    bind(classOf[PlaySessionStore]).to(classOf[PlayCacheSessionStore])

    // callback
    val callbackController = new CallbackController()
callbackController.setDefaultUrl("/?defaulturlafterlogout")
callbackController.setMultiProfile(true)
bind(classOf[CallbackController]).toInstance(callbackController)

    // logout
    val logoutController = new LogoutController()
    logoutController.setDefaultUrl("/")
bind(classOf[LogoutController]).toInstance(logoutController)
}

@Provides
def provideConfig(saml2Client: SAML2Client): Config = {
val clients = new Clients(baseUrl + "/callback", saml2Client)


val config = new Config(clients)
    config.addAuthorizer("custom", new CustomAuthorizer)
config.setHttpActionAdapter(new DefaultHttpActionAdapter())
config

}

}

conf/application.conf

play.http.filters = "filters.Filters"

play.modules.enabled += "modules.SecurityModule"

pac4j.security {
rules = [
{"/index" = {
authorizers = "_authenticated_"
clients = "SAML2Client"
} }
{"/public" = {
authorizers = "_anonymous_"
}}
]
}

controllers/HomeController.scala

@Singleton
class HomeController @Inject()(cc: ControllerComponents, val config: Config, val playSessionStore: PlaySessionStore)
extends AbstractController(cc) with Security[CommonProfile] {

  def index() = Secure("SAML2Client") { profiles: List[CommonProfile] =>

Action { implicit request: Request[AnyContent] =>
Ok(views.html.index("protected index"))
}
}

  def public() = Action { implicit request: Request[AnyContent] =>
Ok(views.html.index("public"))
}
}

controllers/CustomAuthorizer.scala

(copied from your library)

Thanks!
Kevin

 

Kevin Meredith

unread,
Dec 13, 2017, 4:31:19 PM12/13/17
to Pac4j users mailing list
Please ignore my above code review request. I `git clone`'d https://github.com/pac4j/play-pac4j-scala-demo. Then, I modified only the following line from:

val cfg = new SAML2ClientConfiguration("resource:samlKeystore.jks", "pac4j-demo-passwd", "pac4j-demo-passwd", "resource:openidp-feide.xml")

to


val cfg = new SAML2ClientConfiguration("resource:clientkeystore.jks", "changeit", "changeit", "resource:MetaData.xml")

Then, I ran 'sbt run.' With the app running locally, I then navigated to http://localhost:9000/saml/index.html in my browser.

After getting re-directed to the Identity Provider's login, my browser was re-directed to a page that resulted in a POST /callback.

However, I got the same error, which I think is the same as before:

[debug] - org.pac4j.play.filters.SecurityFilter - No authentication needed for /callback
[debug] - org.pac4j.core.engine.DefaultCallbackLogic - === CALLBACK ===
[error] - controllers.CustomErrorHandler - Error occurrred

java.util.concurrent.CompletionException: org.pac4j.core.exception.TechnicalException: name cannot be blank
    at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273)
    at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280)
    at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1592)
    at play.core.j.HttpExecutionContext$$anon$2.run(HttpExecutionContext.scala:56)
    at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:40)
    at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(ForkJoinExecutorConfigurator.scala:43)
    at akka.dispatch.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
    at akka.dispatch.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
    at akka.dispatch.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
    at akka.dispatch.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
Caused by: org.pac4j.core.exception.TechnicalException: name cannot be blank
    at org.pac4j.core.util.CommonHelper.assertTrue(CommonHelper.java:109)
    at org.pac4j.core.util.CommonHelper.assertNotBlank(CommonHelper.java:121)
    at org.pac4j.core.util.CommonHelper.assertNotBlank(CommonHelper.java:131)
    at org.pac4j.core.client.Clients.findClient(Clients.java:145)
    at org.pac4j.core.engine.DefaultCallbackLogic.perform(DefaultCallbackLogic.java:72)
    at org.pac4j.play.CallbackController.lambda$callback$0(CallbackController.java:50)
    at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
    ... 7 common frames omitted

Do you know what this means, please, Jérôme?

Thanks!
Kevin

Jérôme LELEU

unread,
Dec 14, 2017, 11:55:59 AM12/14/17
to Kevin Meredith, Pac4j users mailing list
Hi,

You must not use the Secure function and the SecurityFilter at the same time on the same URL: /index

Can you try just using one of the two mechanisms?

Thanks.
Best regards,
Jérôme


--

Kevin Meredith

unread,
Dec 14, 2017, 12:05:42 PM12/14/17
to Jérôme LELEU, Pac4j users mailing list
Thank you for taking a look!

However, in a follow-up question, I noted that I got the same exception when using your play-pac4j-scala-demo, but I changed only the JKS and XML in the SecurityModule.scala.

In other words, I re-used your code as-is but changed a single line. Yet, I ran into the same run-time exception as before with my code.

Thank you,
Kevin

Jérôme LELEU

unread,
Dec 14, 2017, 12:17:53 PM12/14/17
to Kevin Meredith, Pac4j users mailing list
Hi,

We have an issue with the SAML support in pac4j-saml v2.2.0: can you upgrade to pac4j-saml v2.2.1?
Thanks.
Best regards,
Jérôme

Kevin Meredith

unread,
Dec 14, 2017, 3:15:58 PM12/14/17
to Jérôme LELEU, Pac4j users mailing list
Hi Jérôme-

After upgrading from 2.2.0 to 2.2.1, I still ran into the same run-time exception.

$pwd
/Users/kevinmeredith/Workspace/play-pac4j-scala-demo

$git diff
diff --git a/app/modules/SecurityModule.scala b/app/modules/SecurityModule.scala
index 85b1306..598d717 100644
--- a/app/modules/SecurityModule.scala
+++ b/app/modules/SecurityModule.scala
@@ -78,7 +78,7 @@ class SecurityModule(environment: Environment, configuration: Configuration) ext

 
   @Provides
   def provideSaml2Client: SAML2Client = {
-    val cfg = new SAML2ClientConfiguration("resource:samlKeystore.jks", "pac4j-demo-passwd", "pac4j-demo-passwd", "resource:openidp-feide.xml")
+    val cfg = new SAML2ClientConfiguration("resource:clientkeystore.jks", "changeit", "changeit", "resource:MetaData.xml")
     cfg.setMaximumAuthenticationLifetime(3600)
     cfg.setServiceProviderEntityId("urn:mace:saml:pac4j.org")
     cfg.setServiceProviderMetadataPath(new File("target", "sp-metadata.xml").getAbsolutePath)
diff --git a/bin/activator b/bin/activator
old mode 100644
new mode 100755
diff --git a/build.sbt b/build.sbt
index 83edbca..3b66a49 100644
--- a/build.sbt
+++ b/build.sbt
@@ -7,7 +7,7 @@ lazy val root = (project in file(".")).enablePlugins(PlayScala)
 scalaVersion := "2.12.2"
 
 val playPac4jVersion = "5.0.0-SNAPSHOT"
-val pac4jVersion = "2.2.0"
+val pac4jVersion = "2.2.1"
 val playVersion = "2.6.6"
 
 libraryDependencies ++= Seq(
$


Stack Trace

[debug] - org.pac4j.core.engine.DefaultCallbackLogic - === CALLBACK ===
[error] - controllers.CustomErrorHandler - Error occurrred
java.util.concurrent.CompletionException: org.pac4j.core.exception.TechnicalException: name cannot be blank
    at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273)
    at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280)
    at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1592)
    at play.core.j.HttpExecutionContext$$anon$2.run(HttpExecutionContext.scala:56)
    at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:40)
    at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(ForkJoinExecutorConfigurator.scala:43)
    at akka.dispatch.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
    at akka.dispatch.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
    at akka.dispatch.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
    at akka.dispatch.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
Caused by: org.pac4j.core.exception.TechnicalException: name cannot be blank
    at org.pac4j.core.util.CommonHelper.assertTrue(CommonHelper.java:109)
    at org.pac4j.core.util.CommonHelper.assertNotBlank(CommonHelper.java:121)
    at org.pac4j.core.util.CommonHelper.assertNotBlank(CommonHelper.java:131)
    at org.pac4j.core.client.Clients.findClient(Clients.java:145)
    at org.pac4j.core.engine.DefaultCallbackLogic.perform(DefaultCallbackLogic.java:72)
    at org.pac4j.play.CallbackController.lambda$callback$0(CallbackController.java:50)
    at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
    ... 7 common frames omitted
[debug] - org.pac4j.play.filters.SecurityFilter - No authentication needed for /favicon.ico

Thanks,
Kevin

Kevin Meredith

unread,
Dec 16, 2017, 11:07:41 AM12/16/17
to Jérôme LELEU, Pac4j users mailing list
Any idea, please? Thanks!

Kevin Meredith

unread,
Dec 18, 2017, 1:13:24 PM12/18/17
to Pac4j users mailing list
My Identity Provider added a query parameter to POST /callback for client_name=SAML2Client.

Using the play-pac4j-scala-demo code, but modifying the XML and JKS SAML files, I got the following run-time exception when trying to access GET /saml/index.html:

[debug] - org.pac4j.core.engine.DefaultCallbackLogic - client: #SAML2Client# | name: SAML2Client | callbackUrl: http://kevin-testing.my-app.com:9000/callback?client_name=SAML2Client | urlResolver: org.pac4j.core.http.DefaultUrlResolver@4da28a1e | ajaxRequestResolver: org.pac4j.core.http.DefaultAjaxRequestResolver@7322a889 | includeClientNameInCallbackUrl: true | redirectActionBuilder: null | credentialsExtractor: null | authenticator: null | profileCreator: org.pac4j.core.profile.creator.AuthenticatorProfileCreator@3530b6ff | logoutActionBuilder: org.pac4j.core.logout.NoLogoutActionBuilder@6dbfc3cc | authorizationGenerators: [] |
[error] - org.pac4j.saml.sso.impl.SAML2DefaultResponseValidator - Current assertion validation failed, continue with the next one
org.pac4j.saml.exceptions.SAMLException: Subject confirmation validation failed
    at org.pac4j.saml.sso.impl.SAML2DefaultResponseValidator.validateSubject(SAML2DefaultResponseValidator.java:478)
    at org.pac4j.saml.sso.impl.SAML2DefaultResponseValidator.validateAssertion(SAML2DefaultResponseValidator.java:398)
    at org.pac4j.saml.sso.impl.SAML2DefaultResponseValidator.validateSamlSSOResponse(SAML2DefaultResponseValidator.java:314)
    at org.pac4j.saml.sso.impl.SAML2DefaultResponseValidator.validate(SAML2DefaultResponseValidator.java:142)
    at org.pac4j.saml.sso.impl.SAML2WebSSOMessageReceiver.receiveMessage(SAML2WebSSOMessageReceiver.java:78)
    at org.pac4j.saml.sso.impl.SAML2WebSSOProfileHandler.receive(SAML2WebSSOProfileHandler.java:35)
    at org.pac4j.saml.client.SAML2Client.lambda$clientInit$0(SAML2Client.java:110)
    at org.pac4j.core.client.BaseClient.retrieveCredentials(BaseClient.java:63)
    at org.pac4j.core.client.IndirectClient.getCredentials(IndirectClient.java:125)
    at org.pac4j.core.engine.DefaultCallbackLogic.perform(DefaultCallbackLogic.java:79)

    at org.pac4j.play.CallbackController.lambda$callback$0(CallbackController.java:50)
    at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
    at play.core.j.HttpExecutionContext$$anon$2.run(HttpExecutionContext.scala:56)
    at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:40)
    at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(ForkJoinExecutorConfigurator.scala:43)
    at akka.dispatch.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
    at akka.dispatch.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
    at akka.dispatch.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
    at akka.dispatch.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
[error] - controllers.CustomErrorHandler - Error occurrred
java.util.concurrent.CompletionException: org.pac4j.saml.exceptions.SAMLException: No valid subject assertion found in response

    at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273)
    at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280)
    at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1592)
    at play.core.j.HttpExecutionContext$$anon$2.run(HttpExecutionContext.scala:56)
    at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:40)
    at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(ForkJoinExecutorConfigurator.scala:43)
    at akka.dispatch.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
    at akka.dispatch.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
    at akka.dispatch.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
    at akka.dispatch.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
Caused by: org.pac4j.saml.exceptions.SAMLException: No valid subject assertion found in response
    at org.pac4j.saml.sso.impl.SAML2DefaultResponseValidator.validateSamlSSOResponse(SAML2DefaultResponseValidator.java:325)
    at org.pac4j.saml.sso.impl.SAML2DefaultResponseValidator.validate(SAML2DefaultResponseValidator.java:142)
    at org.pac4j.saml.sso.impl.SAML2WebSSOMessageReceiver.receiveMessage(SAML2WebSSOMessageReceiver.java:78)
    at org.pac4j.saml.sso.impl.SAML2WebSSOProfileHandler.receive(SAML2WebSSOProfileHandler.java:35)
    at org.pac4j.saml.client.SAML2Client.lambda$clientInit$0(SAML2Client.java:110)
    at org.pac4j.core.client.BaseClient.retrieveCredentials(BaseClient.java:63)
    at org.pac4j.core.client.IndirectClient.getCredentials(IndirectClient.java:125)
    at org.pac4j.core.engine.DefaultCallbackLogic.perform(DefaultCallbackLogic.java:79)

    at org.pac4j.play.CallbackController.lambda$callback$0(CallbackController.java:50)
    at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
    ... 7 common frames omitted

Do you have any idea, please, what these new exceptions mean?

Thanks!
Kevin

Jérôme LELEU

unread,
Dec 18, 2017, 1:20:02 PM12/18/17
to Kevin Meredith, Pac4j users mailing list
Hi,

You don't have any subject tag in the SAML response. Generally, it's a matter of configuration on the identity provider side.
Example of a good SAML response:

<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_8e8dc5f69a98cc4c1ff3427e5ce34606fd672f91e6" Version="2.0" IssueInstant="2014-07-17T01:01:48Z" Destination="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685">
  <saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
  </samlp:Status>
  <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="_d71a3a8e9fcc45c9e9d248ef7049393fc8f04e5f75" Version="2.0" IssueInstant="2014-07-17T01:01:48Z">
    <saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer>
    <saml:Subject>
      <saml:NameID SPNameQualifier="http://sp.example.com/demo1/metadata.php" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7</saml:NameID>
      <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml:SubjectConfirmationData NotOnOrAfter="2024-01-18T06:21:48Z" Recipient="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685"/>
      </saml:SubjectConfirmation>
    </saml:Subject>
    <saml:Conditions NotBefore="2014-07-17T01:01:18Z" NotOnOrAfter="2024-01-18T06:21:48Z">
      <saml:AudienceRestriction>
        <saml:Audience>http://sp.example.com/demo1/metadata.php</saml:Audience>
      </saml:AudienceRestriction>
    </saml:Conditions>
    <saml:AuthnStatement AuthnInstant="2014-07-17T01:01:48Z" SessionNotOnOrAfter="2024-07-17T09:01:48Z" SessionIndex="_be9967abd904ddcae3c0eb4189adbe3f71e327cf93">
      <saml:AuthnContext>
        <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
      </saml:AuthnContext>
    </saml:AuthnStatement>
    <saml:AttributeStatement>
      <saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xsi:type="xs:string">test</saml:AttributeValue>
      </saml:Attribute>
      <saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xsi:type="xs:string">te...@example.com</saml:AttributeValue>
      </saml:Attribute>
      <saml:Attribute Name="eduPersonAffiliation" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xsi:type="xs:string">users</saml:AttributeValue>
        <saml:AttributeValue xsi:type="xs:string">examplerole1</saml:AttributeValue>
      </saml:Attribute>
    </saml:AttributeStatement>
  </saml:Assertion>
</samlp:Response>

Thanks.
Best regards,
Jérôme


--
Reply all
Reply to author
Forward
0 new messages