Skip to content

Commit

Permalink
Merge pull request #28 from xp-forge/refactor/xml
Browse files Browse the repository at this point in the history
Refactor CAS authentication flow to use address library
  • Loading branch information
thekid authored Mar 29, 2024
2 parents 67500e2 + 4ffb505 commit 181094b
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 22 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"require" : {
"xp-framework/core": "^12.0 | ^11.0 | ^10.0",
"xp-framework/http": "^10.0 | ^9.0 | ^8.0 | ^7.0",
"xp-framework/xml": "^12.0 | ^11.0 | ^10.0 | ^9.0 | ^8.0",
"xp-forge/address": "^6.0 | ^5.3",
"xp-forge/web": "^4.0 | ^3.0 | ^2.0 | ^1.0",
"xp-forge/json": "^5.0 | ^4.0 | ^3.1",
"xp-forge/sessions": "^3.0 | ^2.0 | ^1.0",
Expand Down
54 changes: 34 additions & 20 deletions src/main/php/web/auth/cas/CasFlow.class.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<?php namespace web\auth\cas;

use lang\Throwable;
use peer\http\HttpConnection;
use util\Objects;
use util\address\{XmlStreaming, ValueOf};
use web\auth\Flow;
use web\{Cookie, Error, Filter};
use xml\XMLFormatException;
use xml\dom\Document;
use xml\parser\{StreamInputSource, XMLParser};

class CasFlow extends Flow {
const SESSION_KEY = 'cas::flow';
Expand Down Expand Up @@ -77,29 +77,43 @@ public function authenticate($request, $response, $session) {
throw new Error($validate->statusCode(), $validate->message());
}

$result= new Document();
try {
(new XMLParser())->withCallback($result)->parse(new StreamInputSource($validate->in()));
} catch (XMLFormatException $e) {
throw new Error(500, 'FORMAT: Validation cannot be parsed', $e);
$stream= new XmlStreaming($validate->in());
$result= $stream->next(new ValueOf([], [
'cas:authenticationFailure' => function(&$self) {
$self['failure']= yield new ValueOf([], [
'@code' => function(&$self) { $self['code']= yield; },
'.' => function(&$self) { $self['message']= trim(yield); },
]);
},
'cas:authenticationSuccess' => function(&$self) {
$self['user']= yield new ValueOf([], [
'cas:user' => function(&$self) { $self['username']= yield; },
'cas:attributes' => function(&$self) {
$self+= yield new ValueOf([], ['*' => function(&$self, $name) {
$self[str_replace('cas:', '', $name)]= yield;
}]);
},
]);
},
'*' => function(&$self, $name) { $self[$name]= yield; },
]));
} catch (Throwable $e) {
throw new Error(500, 'UNEXPECTED: Streaming error', $e);
}

if ($failure= $result->getElementsByTagName('cas:authenticationFailure')) {
throw new Error(500, $failure[0]->getAttribute('code').': '.trim($failure[0]->getContent()));
} else if (!($success= $result->getElementsByTagName('cas:authenticationSuccess'))) {
throw new Error(500, 'UNEXPECTED: '.$result->getSource());
// Success-oriented
if ($user= $result['user'] ?? null) {
$session->register(self::SESSION_KEY, $user);
$session->transmit($response);
$this->finalize($response, $service);
return null;
}

$user= ['username' => $result->getElementsByTagName('cas:user')[0]->getContent()];
if ($attr= $result->getElementsByTagName('cas:attributes')) {
foreach ($attr[0]->getChildren() as $child) {
$user[str_replace('cas:', '', $child->getName())]= $child->getContent();
}
if ($failure= $result['failure'] ?? null) {
throw new Error(500, $result['failure']['code'].': '.$result['failure']['message']);
}

$session->register(self::SESSION_KEY, $user);
$session->transmit($response);
$this->finalize($response, $service);
return null;
throw new Error(500, 'UNEXPECTED: '.Objects::stringOf($result));
}
}
2 changes: 1 addition & 1 deletion src/test/php/web/auth/unittest/CasFlowTest.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ public function validate($ticket, $service) {
$this->authenticate($fixture, '/?ticket='.self::TICKET);
}

#[Test, Expect(class: Error::class, message: '/FORMAT: Validation cannot be parsed/')]
#[Test, Expect(class: Error::class, message: 'UNEXPECTED: []')]
public function shows_error_when_validation_response_not_well_formed() {
$fixture= new class(self::SSO) extends CasFlow {
public function validate($ticket, $service) {
Expand Down

0 comments on commit 181094b

Please sign in to comment.