Silhouette and Angular


#1

Hello,

I am trying to use Silhouette with the npm library ng2-ui-auth. Unfortunately, the sign-in with Google does not seem to work, as I get a: [Silhouette][JcaSigner] Invalid message format; Expected [VERSION]-[SIGNATURE]-[DATA] after being redirected to Google. I guess this is a setup issue but I do not see what is expected exactly from a Silhouette point of view.

Cheers


#2

Hi,

It seems that Silhouette tries to validate the OAuth2 state param which it passes normally if you start the authentication process over Silhouette. This validation must be turned off for client side authentication. Which version of Silhouette do you use?

Beast regards,
Christian


#3

The very latest one: 5.0.0-RC2


#4

OK, then you must remove the CsrfState from your bindings.


#5

Got it thanks, I am now trying to look at the angular seed and I see that the bindings do not exist. One thing I do not see how to do though is that in the seed there is this binding:

bind[OAuth2StateProvider].to[DummyStateProvider]

I am trying to do the same with the SocialStateProvider but I cannot see any DummyStateProvider in version 5.0.0 and I do not really understand what the migration guide says regarding this point.


#6

I tried to implement this:

@Provides
def provideSocialStateHandler(
  @Named("social-state-signer") signer: Signer): SocialStateHandler = {

  new DefaultSocialStateHandler(Set(), signer)
}

But I still get the same error as in my initial post :-/.


#7

Sorry to be painful, but I am not sure I understand what I need to do. Right now, my code is using the DefaultSocialStateHandler which is trying to use the JcaSigner to extract information from the state passed by the client. And the step seems to fail because the state is not well formed. Could you explain to me what I should disable? I do not have any reference to CsrfState right now.


#8

I am trying to look at various seeds, but all the ones that were using the previous DummyStateProvider just removed all references to it without replacement - they usually remove the clef bindings.


#9

I did find the commit removing what was used with previous Silhouette version: https://github.com/mohiva/play-silhouette/commit/f725261e831a0230fc7a0fd9d874e10aa7e3cc08

I am just not sure how to do now :-/. Any help would be more than appreciated :).


#10

I had the same issue trying to replicate client-side authentication that I had working in Silhouette 3.x on Play 2.4

Since I am not passing back any state from the client, I created a DummySocialStateHandler that did not require a Signer

class DummySocialStateHandler(override val handlers: Set[SocialStateItemHandler])
  extends SocialStateHandler {

  override type Self = DummySocialStateHandler

  override def withHandler(handler: SocialStateItemHandler): DummySocialStateHandler = {
    new DummySocialStateHandler(handlers + handler)
  }

  override def state(implicit ec: ExecutionContext): Future[SocialState] = {
    Future.sequence(handlers.map(_.item)).map(items => SocialState(items.toSet))
  }

  override def unserialize[B](state: String)(
    implicit
    request: ExtractableRequest[B],
    ec: ExecutionContext
  ): Future[SocialState] = {
      Future.successful(SocialState(Set()))
  }

  override def serialize(state: SocialState): String = ""

  override def publish[B](result: Result, state: SocialState)(implicit request: ExtractableRequest[B]): Result = {
    handlers.collect { case h: PublishableSocialStateItemHandler => h }.foldLeft(result) { (r, handler) =>
      state.items.foldLeft(r) { (r, item) =>
        handler.canHandle(item).map(item => handler.publish(item, r)).getOrElse(result)
      }
    }
  }

}

In my SilhouetteModule, I created a provider for the DummySocialStateHandler

@Provides
  def provideSocialStateHandler(): SocialStateHandler = {
    new DummySocialStateHandler(Set())
  }

This seemed to resolve this issue. However, a potentially better solution would be to have DefaultSocialStateProvider determine if the State is set first before attempting to extract (SocialStateProvider.scala:269).


#11

Hi,

this is indeed an issue.

However, a potentially better solution would be to have DefaultSocialStateProvider determine if the State is set first before attempting to extract (SocialStateProvider.scala:269).

This won’t work, because then an attacker could only omit the state param to disable the state validation. The CSRF state validation exists only to avoid such attacks.

Generally it’s a potential security issue if the CSRF token isn’t included in the OAuth flow. So from a security standpoint it would be preferred to pass the state also from the client side. The client could issue the state value from the backend and include it in the authentication request.

Anyway, it would be good if the state validation would check if a state item handler is registered and then either enable or disable state validation. So the client is responsible for the activation of the state validation and not an attacker.

I’ll fix this issue in the next days and release a new RC.

Best regards,
Christian


#12

That’s great news. A small update in the documentation to explain how to do that would be great ;-).


#13

I’ve released version 5.0.0-RC3


#14

Works fine now with the code I posted above:

@Provides
def provideSocialStateHandler(
  @Named("social-state-signer") signer: Signer): SocialStateHandler = {

  new DefaultSocialStateHandler(Set(), signer)
}

Thanks!