Skip to content

Commit cf2cdb1

Browse files
author
Moroine Bentefrit
authored
Merge pull request #9 from AdactiveSAS/release/0.7.0
Release/0.7.0
2 parents f393468 + 63b4867 commit cf2cdb1

10 files changed

Lines changed: 205 additions & 31 deletions

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# CHANGELOG
2+
3+
## v0.7.0
4+
5+
### Add
6+
- Default Logger into `adactive_sas_saml2_bridge.processor.hosted_idp` service
7+
- ServiceProvider option `maxRetryLogin` to setup the number of login retry in case of errors. The default is `0` to
8+
keep retro-compatibility
9+
10+
### Fix
11+
- SLS initiated by IDP
12+
- composer
13+

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ class SamlServiceProviderRepository implements ServiceProviderRepository
175175
}
176176
```
177177

178-
######Slack example
178+
###### Slack example
179179
```
180180
$this->spMap["https://slack.com"] = new ServiceProvider(
181181
[
@@ -239,7 +239,7 @@ $this->spMap["https://slack.com"] = new ServiceProvider(
239239
);
240240

241241
```
242-
######Freshdesk example
242+
###### Freshdesk example
243243
```
244244
$this->spMap["https://$freshdeskAccountName.freshdesk.com"] = new ServiceProvider(
245245
[

src/DependencyInjection/AdactiveSasSaml2BridgeExtension.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ private function parseHostedIdpConfiguration(array $identityProvider, ContainerB
9191
]
9292
);
9393
$idpDefinition->addTag("kernel.event_subscriber");
94+
$idpDefinition->addMethodCall("setLogger", [new Reference("logger")]);
9495
$container->setDefinition("adactive_sas_saml2_bridge.processor.hosted_idp", $idpDefinition);
9596
}
9697
}

src/Entity/ServiceProvider.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,12 @@ public function getNameQualifier()
124124
{
125125
return $this->get('NameQualifier');
126126
}
127+
128+
/**
129+
* @return int
130+
*/
131+
public function getMaxRetryLogin()
132+
{
133+
return $this->get('maxRetryLogin', 0);
134+
}
127135
}

src/SAML2/Binding/HttpBindingInterface.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ public function receiveSignedAuthnRequest(Request $request);
5959
*/
6060
public function receiveSignedLogoutRequest(Request $request);
6161

62+
/**
63+
* @param Request $request
64+
* @return \SAML2_LogoutResponse
65+
*/
66+
public function receiveSignedLogoutResponse(Request $request);
67+
6268
/**
6369
* @param Request $request
6470
* @return \SAML2_AuthnRequest
@@ -71,6 +77,12 @@ public function receiveUnsignedAuthnRequest(Request $request);
7177
*/
7278
public function receiveUnsignedLogoutRequest(Request $request);
7379

80+
/**
81+
* @param Request $request
82+
* @return \SAML2_LogoutResponse
83+
*/
84+
public function receiveUnsignedLogoutResponse(Request $request);
85+
7486
/**
7587
* @param Request $request
7688
* @return \SAML2_Message

src/SAML2/Binding/HttpPostBinding.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,16 @@ public function receiveSignedLogoutRequest(Request $request)
127127
throw new UnsupportedBindingException("Unsupported binding: signed POST LogoutRequest is not supported at the moment");
128128
}
129129

130+
/**
131+
* @param Request $request
132+
* @return \SAML2_LogoutResponse
133+
* @throws \AdactiveSas\Saml2BridgeBundle\SAML2\Binding\Exception\UnsupportedBindingException
134+
*/
135+
public function receiveSignedLogoutResponse(Request $request)
136+
{
137+
throw new UnsupportedBindingException("Unsupported binding: signed POST LogoutResponse is not supported at the moment");
138+
}
139+
130140
/**
131141
* @param Request $request
132142
* @return \SAML2_AuthnRequest
@@ -147,6 +157,16 @@ public function receiveUnsignedLogoutRequest(Request $request)
147157
throw new UnsupportedBindingException("Unsupported binding: unsigned POST LogoutRequest is not supported at the moment");
148158
}
149159

160+
/**
161+
* @param Request $request
162+
* @return \SAML2_LogoutResponse
163+
* @throws \AdactiveSas\Saml2BridgeBundle\SAML2\Binding\Exception\UnsupportedBindingException
164+
*/
165+
public function receiveUnsignedLogoutResponse(Request $request)
166+
{
167+
throw new UnsupportedBindingException("Unsupported binding: unsigned POST LogoutResponse is not supported at the moment");
168+
}
169+
150170
/**
151171
* @param Request $request
152172
* @return \SAML2_Message

src/SAML2/Binding/HttpRedirectBinding.php

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,24 @@ public function receiveSignedLogoutRequest(Request $request){
222222
return $message;
223223
}
224224

225+
/**
226+
* @param Request $request
227+
* @return \SAML2_LogoutResponse
228+
* @throws \AdactiveSas\Saml2BridgeBundle\Exception\InvalidArgumentException
229+
*/
230+
public function receiveSignedLogoutResponse(Request $request){
231+
$message = $this->receiveSignedMessage($request);
232+
233+
if (!$message instanceof \SAML2_LogoutResponse) {
234+
throw new InvalidArgumentException(sprintf(
235+
'The received request is not an LogoutRequest, "%s" received instead',
236+
substr(get_class($message), strrpos($message, '_') + 1)
237+
));
238+
}
239+
240+
return $message;
241+
}
242+
225243
/**
226244
* @param Request $request
227245
* @return \SAML2_AuthnRequest
@@ -251,7 +269,25 @@ public function receiveUnsignedLogoutRequest(Request $request){
251269
if (!$message instanceof \SAML2_LogoutRequest) {
252270
throw new InvalidArgumentException(sprintf(
253271
'The received request is not an LogoutRequest, "%s" received instead',
254-
substr(get_class($message), strrpos($message, '_') + 1)
272+
substr(get_class($message), strrpos(get_class($message), '_') + 1)
273+
));
274+
}
275+
276+
return $message;
277+
}
278+
279+
/**
280+
* @param Request $request
281+
* @return \SAML2_LogoutResponse
282+
* @throws \AdactiveSas\Saml2BridgeBundle\Exception\InvalidArgumentException
283+
*/
284+
public function receiveUnsignedLogoutResponse(Request $request){
285+
$message = $this->receiveUnsignedMessage($request);
286+
287+
if (!$message instanceof \SAML2_LogoutResponse) {
288+
throw new InvalidArgumentException(sprintf(
289+
'The received request is not an LogoutRequest, "%s" received instead',
290+
substr(get_class($message), strrpos(get_class($message), '_') + 1)
255291
));
256292
}
257293

src/SAML2/Provider/HostedIdentityProviderProcessor.php

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -188,11 +188,15 @@ public function onKernelResponse(FilterResponseEvent $event)
188188
if ($this->stateHandler->can(SamlStateHandler::TRANSITION_SSO_RESPOND)) {
189189
$event->setResponse($this->continueSingleSignOn());
190190
return;
191+
}else{
192+
$this->logger->debug("Cannot TRANSITION_SSO_RESPOND, state is ". $this->stateHandler->get()->getState());
191193
}
192194

193-
if ($this->stateHandler->can(SamlStateHandler::TRANSITION_SLS_RESPOND)) {
195+
if ($this->stateHandler->can(SamlStateHandler::TRANSITION_SLS_RESPOND, false)) {
194196
$event->setResponse($this->continueSingleLogoutService());
195197
return;
198+
}else{
199+
$this->logger->debug("Cannot TRANSITION_SLS_RESPOND, state is ". $this->stateHandler->get()->getState());
196200
}
197201
}
198202

@@ -206,6 +210,10 @@ public function onAuthenticationSuccess(CoreAuthenticationEvent $event)
206210
return;
207211
}
208212

213+
if($this->stateHandler->has()){
214+
$this->stateHandler->get()->resetLoginRetryCount();
215+
}
216+
209217
$user = $event->getAuthenticationToken()->getUser();
210218
if ($this->stateHandler->has()
211219
&& $user instanceof UserInterface && $this->stateHandler->has()) {
@@ -233,6 +241,19 @@ public function onAuthenticationFailure(CoreAuthenticationFailureEvent $event)
233241
return;
234242
}
235243

244+
if($this->stateHandler->has()){
245+
/** @var \SAML2_AuthnRequest $authRequest */
246+
$authRequest = $this->stateHandler->get()->getRequest();
247+
248+
$sp = $this->getServiceProvider($authRequest->getIssuer());
249+
250+
if($this->stateHandler->get()->getLoginRetryCount() < $sp->getMaxRetryLogin()){
251+
$this->stateHandler->get()->incrementLoginRetryCount();
252+
$this->logger->debug("Login failed, retrying");
253+
return;
254+
}
255+
}
256+
236257
$this->logger->notice("Authentication failed");
237258
$this->stateHandler->apply(SamlStateHandler::TRANSITION_SSO_AUTHENTICATE_FAIL);
238259
}
@@ -247,10 +268,7 @@ public function onLogoutSuccess(LogoutEvent $event)
247268
$this->stateHandler->resume(true);
248269
$this->stateHandler->get()->setOriginalLogoutResponse($event->getResponse());
249270

250-
$this->stateHandler
251-
->apply(SamlStateHandler::TRANSITION_SLS_START)
252-
->apply(SamlStateHandler::TRANSITION_SLS_START_DISPATCH)
253-
->apply(SamlStateHandler::TRANSITION_SLS_END_DISPATCH);
271+
$this->stateHandler->apply(SamlStateHandler::TRANSITION_SLS_START_BY_IDP);
254272

255273
return;
256274
}
@@ -291,7 +309,7 @@ public function processSingleSignOn(Request $httpRequest)
291309
$authRequest = $inputBinding->receiveSignedAuthnRequest($httpRequest);
292310
}
293311

294-
$this->validateRequest($authRequest);
312+
$this->validateMessage($authRequest);
295313

296314
$event = new ReceiveAuthnRequestEvent($authRequest, $this->identityProvider, $this->stateHandler);
297315
$this->eventDispatcher->dispatch(Saml2Events::SSO_AUTHN_RECEIVE_REQUEST, $event);
@@ -386,12 +404,7 @@ public function processSingleLogoutService(Request $httpRequest)
386404
$inputBinding = $this->bindingContainer->get($this->identityProvider->getSlsBinding());
387405

388406
try {
389-
$logoutMessage = $inputBinding->receiveUnsignedLogoutRequest($httpRequest);
390-
$sp = $this->getServiceProvider($logoutMessage->getIssuer());
391-
if ($sp->wantSignedLogoutRequest()) {
392-
$logoutMessage = $inputBinding->receiveSignedLogoutRequest($httpRequest);
393-
}
394-
$this->validateRequest($logoutMessage);
407+
$logoutMessage = $inputBinding->receiveUnsignedMessage($httpRequest);
395408
} catch (\Throwable $e) {
396409
// handle error, apparently the request cannot be processed :(
397410
$msg = sprintf('Could not process Request, error: "%s"', $e->getMessage());
@@ -401,6 +414,12 @@ public function processSingleLogoutService(Request $httpRequest)
401414
}
402415

403416
if ($logoutMessage instanceof \SAML2_LogoutRequest) {
417+
$sp = $this->getServiceProvider($logoutMessage->getIssuer());
418+
if ($sp->wantSignedLogoutRequest()) {
419+
$logoutMessage = $inputBinding->receiveSignedLogoutRequest($httpRequest);
420+
}
421+
$this->validateMessage($logoutMessage);
422+
404423
$this->logger->notice('Received LogoutRequest, started processing');
405424

406425
$this->stateHandler->resume(true)->apply(SamlStateHandler::TRANSITION_SLS_START);
@@ -414,6 +433,12 @@ public function processSingleLogoutService(Request $httpRequest)
414433
}
415434

416435
if ($logoutMessage instanceof \SAML2_LogoutResponse) {
436+
$sp = $this->getServiceProvider($logoutMessage->getIssuer());
437+
if ($sp->wantSignedLogoutResponse()) {
438+
$logoutMessage = $inputBinding->receiveSignedLogoutResponse($httpRequest);
439+
}
440+
$this->validateMessage($logoutMessage);
441+
417442
$this->logger->notice('Received LogoutResponse, continue processing');
418443
$this->stateHandler->apply(SamlStateHandler::TRANSITION_SLS_END_PROPAGATE);
419444

@@ -455,6 +480,8 @@ public function continueSingleLogoutService()
455480

456481
$outBinding = $this->bindingContainer->get($sp->getSingleLogoutBinding());
457482

483+
$this->logger->notice(sprintf('Propagate logout to sp %s',$sp->getSingleLogoutUrl()));
484+
458485
if ($sp->wantSignedLogoutRequest()) {
459486
$response = $outBinding->getSignedRequest($logoutRequest);
460487
} else {
@@ -474,6 +501,8 @@ public function continueSingleLogoutService()
474501
$sp = $this->getServiceProvider($logoutRequest->getIssuer());
475502
$outBinding = $this->bindingContainer->get($sp->getSingleLogoutBinding());
476503

504+
$this->logger->notice(sprintf('Logout: Respond to sp initiator %s',$sp->getEntityId()));
505+
477506
if ($sp->wantSignedLogoutResponse()) {
478507
$response = $outBinding->getSignedResponse($logoutResponse);
479508
} else {
@@ -498,6 +527,8 @@ public function continueSingleLogoutService()
498527

499528
$this->stateHandler->resume();
500529

530+
$this->logger->notice('Saml: Logout terminated');
531+
501532
return $response;
502533
}
503534

@@ -682,19 +713,15 @@ protected function getIdentityProviderXmlPublicKey()
682713
}
683714

684715
/**
685-
* @param \SAML2_Request $request
716+
* @param \SAML2_Message $message
686717
*/
687-
protected function validateRequest(\SAML2_Request $request)
718+
protected function validateMessage(\SAML2_Message $message)
688719
{
689-
if (!$this->serviceProviderRepository->hasServiceProvider($request->getIssuer())) {
690-
throw new UnknownServiceProviderException($request->getIssuer());
691-
}
692-
693-
if (!$this->identityProvider->wantSignedAuthnRequest()) {
694-
return;
720+
if (!$this->serviceProviderRepository->hasServiceProvider($message->getIssuer())) {
721+
throw new UnknownServiceProviderException($message->getIssuer());
695722
}
696723

697-
$serviceProvider = $this->getServiceProvider($request->getIssuer());
724+
$serviceProvider = $this->getServiceProvider($message->getIssuer());
698725

699726
$this->logger->debug(sprintf('Extracting public keys for ServiceProvider "%s"', $serviceProvider->getEntityId()));
700727

@@ -715,7 +742,7 @@ protected function validateRequest(\SAML2_Request $request)
715742
$key = new \XMLSecurityKey(\XMLSecurityKey::RSA_SHA256, array('type' => 'public'));
716743
$key->loadKey($x509Key->getCertificate());
717744

718-
$request->validate($key);
745+
$message->validate($key);
719746
}
720747
}
721748
}

src/SAML2/State/SamlState.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ class SamlState
4646
*/
4747
protected $originalLogoutResponse;
4848

49+
/**
50+
* @var int
51+
*/
52+
protected $loginRetryCount;
53+
4954
/**
5055
* @var null|string
5156
*/
@@ -58,6 +63,7 @@ public function __construct()
5863
{
5964
$this->state = self::STATE_INITIAL;
6065
$this->serviceProvidersIds = [];
66+
$this->loginRetryCount = 0;
6167
}
6268

6369
/**
@@ -228,4 +234,40 @@ public function setAuthnContext($authnContext)
228234
$this->authnContext = $authnContext;
229235
return $this;
230236
}
237+
238+
/**
239+
* @return int
240+
*/
241+
public function getLoginRetryCount()
242+
{
243+
return $this->loginRetryCount;
244+
}
245+
246+
/**
247+
* @param int $loginRetryCount
248+
* @return SamlState
249+
*/
250+
public function setLoginRetryCount($loginRetryCount)
251+
{
252+
$this->loginRetryCount = $loginRetryCount;
253+
return $this;
254+
}
255+
256+
/**
257+
* @return SamlState
258+
*/
259+
public function incrementLoginRetryCount()
260+
{
261+
$this->loginRetryCount++;
262+
return $this;
263+
}
264+
265+
/**
266+
* @return SamlState
267+
*/
268+
public function resetLoginRetryCount()
269+
{
270+
$this->loginRetryCount = 0;
271+
return $this;
272+
}
231273
}

0 commit comments

Comments
 (0)