From 7c693425deded0bd1529f3ba44d0e3a1db516090 Mon Sep 17 00:00:00 2001 From: Rico Leuthold Date: Sun, 26 Mar 2023 19:01:11 +0200 Subject: [PATCH] WIP. XML login request. --- src/Methods/CheckConnection.php | 41 ++++++++--- src/Methods/Method.php | 46 +++++++++---- src/XML/MedidocXML.php | 55 +++++++++++++++ src/XML/MedidocXMLService.php | 57 ---------------- src/XML/Nodes/Body.php | 16 +++-- src/XML/Nodes/Envelope.php | 36 ---------- src/XML/Nodes/Envelope/Action.php | 2 + src/XML/Nodes/Envelope/LoginSecurity.php | 35 ++++++++++ src/XML/Nodes/Envelope/ReplyTo.php | 2 +- src/XML/Nodes/Envelope/Security.php | 5 +- .../Security/SecurityContextToken.php | 5 +- src/XML/Nodes/Envelope/Security/Signature.php | 3 + .../Envelope/Security/Signature/KeyInfo.php | 7 +- .../Security/Signature/SignatureValue.php | 3 + .../Security/Signature/SignedInfo.php | 3 + .../Signature/SignedInfo/Reference.php | 4 +- .../SignedInfo/Reference/DigestValue.php | 8 +-- src/XML/Nodes/Envelope/Security/Timestamp.php | 7 +- .../Nodes/Envelope/Security/UsernameToken.php | 47 +++++++++++++ src/XML/Nodes/Header.php | 14 ++++ src/XML/Nodes/Node.php | 68 ++++++++++++++++--- src/XML/XML_NS.php | 3 +- 22 files changed, 319 insertions(+), 148 deletions(-) create mode 100644 src/XML/MedidocXML.php delete mode 100644 src/XML/MedidocXMLService.php delete mode 100644 src/XML/Nodes/Envelope.php create mode 100644 src/XML/Nodes/Envelope/LoginSecurity.php create mode 100644 src/XML/Nodes/Envelope/Security/UsernameToken.php create mode 100644 src/XML/Nodes/Header.php diff --git a/src/Methods/CheckConnection.php b/src/Methods/CheckConnection.php index 0bc9b03..131f886 100644 --- a/src/Methods/CheckConnection.php +++ b/src/Methods/CheckConnection.php @@ -2,22 +2,43 @@ namespace Smartprax\Medidoc\Methods; +use Ramsey\Uuid\Uuid; use Sabre\Xml\Writer; +use Smartprax\Medidoc\XML\Nodes\Envelope\Security\Timestamp; +use Smartprax\Medidoc\XML\Nodes\Node; +use Smartprax\Medidoc\XML\XML_NS; class CheckConnection extends Method { public function xmlSerialize(Writer $writer): void { - $writer->write([ - [ - 'name' => 'gln', - 'value' => \config('medidoc.gln') - ], - [ - 'name' => 'password', - 'value' => \config('medidoc.password') - ], - ]); + $writer->write( + Node::create( + name: XML_NS::trust->clark('RequestSecurityToken'), + value: [ + Node::create( + name: XML_NS::trust->clark('TokenType'), + value: 'http://schemas.xmlsoap.org/ws/2005/02/sc/sct'), + Node::create(name: XML_NS::trust->clark('RequestType'), value: 'http://schemas.xmlsoap.org/ws/2005/02/trust/Issue'), + Node::create(name: XML_NS::trust->clark('Entropy'), value: [ + Node::create(name: XML_NS::trust->clark('BinarySecret'), attributes: [ + XML_NS::wss_utility->attribute('id') => 'uuid-' . Uuid::uuid4() . '-1', + 'Type' => 'http://schemas.xmlsoap.org/ws/2005/02/trust/Nonce', + ], value: \base64_encode( + pack( + 'H*', + sha1( + pack('H*', mt_rand()) . + pack('a*', Timestamp::create($this)->created()) . + pack('a*', \config('medidoc.encryption_key')) + ) + ) + ) + ) + ]), + ] + ) + ); } } diff --git a/src/Methods/Method.php b/src/Methods/Method.php index 22c376b..512f846 100644 --- a/src/Methods/Method.php +++ b/src/Methods/Method.php @@ -10,7 +10,15 @@ use Lorisleiva\Actions\Concerns\AsCommand; use Ramsey\Uuid\Uuid; use Sabre\Xml\XmlSerializable; -use Smartprax\Medidoc\XML\MedidocXMLService; +use Smartprax\Medidoc\XML\MedidocXML; +use Smartprax\Medidoc\XML\Nodes\Body; +use Smartprax\Medidoc\XML\Nodes\Envelope\Action; +use Smartprax\Medidoc\XML\Nodes\Envelope\LoginSecurity; +use Smartprax\Medidoc\XML\Nodes\Envelope\MessageID; +use Smartprax\Medidoc\XML\Nodes\Envelope\ReplyTo; +use Smartprax\Medidoc\XML\Nodes\Envelope\Security; +use Smartprax\Medidoc\XML\Nodes\Envelope\To; +use Smartprax\Medidoc\XML\Nodes\Header; abstract class Method implements XmlSerializable { @@ -68,27 +76,37 @@ public function messageId() : string return CarbonImmutable::now('GMT'); } - public function call() - { - $this->handle(); - } - public function handle() : string { - $this->login(); - return MedidocXMLService::make($this)->prettyPrint(); + return $this->login(); + + //return $this->call(); } - public function login() + public function login() : string { - $login_xml = MedidocXMLService::make($this)->write([ - - ]); + return MedidocXML::write( + Header::create() + ->addChild(new Action($this)) + ->addChild(new MessageID()) + ->addChild(new ReplyTo()) + ->addChild(new To()) + ->addChild(new LoginSecurity($this)), + new Body($this)); } - - + public function call() : string + { + return MedidocXML::write( + Header::create() + ->addChild(new Action($this)) + ->addChild(new MessageID()) + ->addChild(new ReplyTo()) + ->addChild(new To()) + ->addChild(new Security($this)), + new Body($this)); + } public function getCommandSignature() :string { diff --git a/src/XML/MedidocXML.php b/src/XML/MedidocXML.php new file mode 100644 index 0000000..ed7c03a --- /dev/null +++ b/src/XML/MedidocXML.php @@ -0,0 +1,55 @@ +writer = New Writer(); + $this->writer->openMemory(); + $this->writer->setIndent(true); + $this->writer->startDocument('1.0', 'UTF-8'); + + foreach (XML_NS::cases() as $namespace) { + $this->writer->namespaceMap[$namespace->value] = $namespace->name; + } + + } + + public static function write(Header $header, Body $body) : self + { + $instance = new self(); + + $instance->writer->writeElement(XML_NS::envelope->clark('Envelope'), [ + $header, + $body, + ]); + + return $instance; + } + + + public function prettyPrint() : string + { + $dom = new \DOMDocument('1.0'); + $dom->preserveWhiteSpace = true; + $dom->formatOutput = true; + $dom->loadXML($this->writer->outputMemory()); + + return $dom->saveXML(); + } + + public function __toString(): string + { + return $this->writer->outputMemory(); + } + +} diff --git a/src/XML/MedidocXMLService.php b/src/XML/MedidocXMLService.php deleted file mode 100644 index debf9a8..0000000 --- a/src/XML/MedidocXMLService.php +++ /dev/null @@ -1,57 +0,0 @@ -openMemory(); - $this->setIndent(true); - $this->startDocument('1.0', 'UTF-8'); - - $this->initNamespacesMap(); - } - - private function initNamespacesMap() - { - foreach (XML_NS::cases() as $namespace) { - $this->namespaceMap[$namespace->value] = $namespace->name; - } - } - - public static function make(Method $method) : self - { - $instance = new self(); - - $instance->writeElement(XML_NS::envelope->node('Envelope'), [ - new Envelope($method), - new Body($method), - ]); - - return $instance; - } - - - public function prettyPrint() : string - { - $dom = new \DOMDocument('1.0'); - $dom->preserveWhiteSpace = true; - $dom->formatOutput = true; - $dom->loadXML($this->outputMemory()); - - return $dom->saveXML(); - } - - public function __toString(): string - { - return $this->outputMemory(); - } - -} diff --git a/src/XML/Nodes/Body.php b/src/XML/Nodes/Body.php index 2200b78..3ed6c70 100644 --- a/src/XML/Nodes/Body.php +++ b/src/XML/Nodes/Body.php @@ -2,22 +2,26 @@ namespace Smartprax\Medidoc\XML\Nodes; +use Sabre\Xml\Writer; +use Smartprax\Medidoc\Methods\Method; use Smartprax\Medidoc\XML\XML_NS; class Body extends Node { - public function namespace(): ?XML_NS + public Method $method; + + public function __construct(Method $method) { - return XML_NS::envelope; + $this->method = $method; } - public function attributes(): array + public function namespace(): ?XML_NS { - return []; + return XML_NS::envelope; } - public function value(): array + public function xmlSerialize(Writer $writer): void { - return []; + $this->method->xmlSerialize($writer); } } diff --git a/src/XML/Nodes/Envelope.php b/src/XML/Nodes/Envelope.php deleted file mode 100644 index 780695e..0000000 --- a/src/XML/Nodes/Envelope.php +++ /dev/null @@ -1,36 +0,0 @@ -method), - new MessageID($this->method), - new ReplyTo($this->method), - new To($this->method), - new Security($this->method) - ]; - } -} diff --git a/src/XML/Nodes/Envelope/Action.php b/src/XML/Nodes/Envelope/Action.php index a93c72a..70a6ae6 100644 --- a/src/XML/Nodes/Envelope/Action.php +++ b/src/XML/Nodes/Envelope/Action.php @@ -8,6 +8,8 @@ class Action extends \Smartprax\Medidoc\XML\Nodes\Node { + public function __construct(protected Method $method) {} + public function namespace(): ?XML_NS { return XML_NS::addressing; diff --git a/src/XML/Nodes/Envelope/LoginSecurity.php b/src/XML/Nodes/Envelope/LoginSecurity.php new file mode 100644 index 0000000..80f4871 --- /dev/null +++ b/src/XML/Nodes/Envelope/LoginSecurity.php @@ -0,0 +1,35 @@ +attribute('mustUnderstand') => '1' + ]; + } + + public function value(): array + { + return [ + new Timestamp($this->method), + new UsernameToken(), + ]; + } +} diff --git a/src/XML/Nodes/Envelope/ReplyTo.php b/src/XML/Nodes/Envelope/ReplyTo.php index 4df2677..7b2ed96 100644 --- a/src/XML/Nodes/Envelope/ReplyTo.php +++ b/src/XML/Nodes/Envelope/ReplyTo.php @@ -21,7 +21,7 @@ public function attributes(): array public function value(): string|array { return [ - 'name' => XML_NS::addressing->node('Address'), + 'name' => XML_NS::addressing->clark('Address'), 'value' => 'http://www.w3.org/2005/08/addressing/anonymous' ]; } diff --git a/src/XML/Nodes/Envelope/Security.php b/src/XML/Nodes/Envelope/Security.php index 2883bad..2bbf635 100644 --- a/src/XML/Nodes/Envelope/Security.php +++ b/src/XML/Nodes/Envelope/Security.php @@ -2,6 +2,7 @@ namespace Smartprax\Medidoc\XML\Nodes\Envelope; +use Smartprax\Medidoc\Methods\Method; use Smartprax\Medidoc\XML\Nodes\Envelope\Security\SecurityContextToken; use Smartprax\Medidoc\XML\Nodes\Envelope\Security\Timestamp; use Smartprax\Medidoc\XML\Nodes\Node; @@ -10,6 +11,8 @@ class Security extends Node { + public function __construct(protected Method $method) {} + public function namespace(): ?XML_NS { return XML_NS::wss_secext; @@ -26,7 +29,7 @@ public function value(): array { return [ new Timestamp($this->method), - $this->method->loggedIn() ? new SecurityContextToken($this->method) : new UsernameToken, + new SecurityContextToken($this->method), ]; } } diff --git a/src/XML/Nodes/Envelope/Security/SecurityContextToken.php b/src/XML/Nodes/Envelope/Security/SecurityContextToken.php index 6a369da..d8a8412 100644 --- a/src/XML/Nodes/Envelope/Security/SecurityContextToken.php +++ b/src/XML/Nodes/Envelope/Security/SecurityContextToken.php @@ -3,11 +3,14 @@ namespace Smartprax\Medidoc\XML\Nodes\Envelope\Security; use Ramsey\Uuid\Uuid; +use Smartprax\Medidoc\Methods\Method; use Smartprax\Medidoc\XML\XML_NS; class SecurityContextToken extends \Smartprax\Medidoc\XML\Nodes\Node { + public function __construct(protected Method $method) {} + public function namespace(): ?XML_NS { return XML_NS::sc; @@ -24,7 +27,7 @@ public function value(): string|array { return [ [ - 'name' => XML_NS::sc->node('Identifier'), + 'name' => XML_NS::sc->clark('Identifier'), 'value' => 'urn:uuid:' . Uuid::uuid4(), ] ]; diff --git a/src/XML/Nodes/Envelope/Security/Signature.php b/src/XML/Nodes/Envelope/Security/Signature.php index 717cc2a..5bab5f6 100644 --- a/src/XML/Nodes/Envelope/Security/Signature.php +++ b/src/XML/Nodes/Envelope/Security/Signature.php @@ -3,6 +3,7 @@ namespace Smartprax\Medidoc\XML\Nodes\Envelope\Security; use DOMDocument; +use Smartprax\Medidoc\Methods\Method; use Smartprax\Medidoc\XML\Nodes\Envelope\Security\Signature\SignatureValue; use Smartprax\Medidoc\XML\Nodes\Envelope\Security\Signature\SignedInfo; use Smartprax\Medidoc\XML\XML_NS; @@ -10,6 +11,8 @@ class Signature extends \Smartprax\Medidoc\XML\Nodes\Node { + public function __construct(protected Method $method) {} + public function namespace(): ?XML_NS { return null; diff --git a/src/XML/Nodes/Envelope/Security/Signature/KeyInfo.php b/src/XML/Nodes/Envelope/Security/Signature/KeyInfo.php index 2b63c91..a0fc41b 100644 --- a/src/XML/Nodes/Envelope/Security/Signature/KeyInfo.php +++ b/src/XML/Nodes/Envelope/Security/Signature/KeyInfo.php @@ -2,12 +2,15 @@ namespace Smartprax\Medidoc\XML\Nodes\Envelope\Security\Signature; +use Smartprax\Medidoc\Methods\Method; use Smartprax\Medidoc\XML\Nodes\Node; use Smartprax\Medidoc\XML\XML_NS; class KeyInfo extends Node { + public function __construct(protected Method $method) {} + public function namespace(): ?XML_NS { return null; @@ -22,10 +25,10 @@ public function value(): string|array { return [ [ - 'name' => XML_NS::wss_secext->node('SecurityTokenReference'), + 'name' => XML_NS::wss_secext->clark('SecurityTokenReference'), 'value' => [ [ - 'name' => XML_NS::wss_secext->node('Reference'), + 'name' => XML_NS::wss_secext->clark('Reference'), 'attributes' => [ 'ValueTupe' => 'http://schemas.xmlsoap.org/ws/2005/02/sc/sct', 'URI' => '#uuid-' . $this->method->uuid(), diff --git a/src/XML/Nodes/Envelope/Security/Signature/SignatureValue.php b/src/XML/Nodes/Envelope/Security/Signature/SignatureValue.php index c976de6..96a4040 100644 --- a/src/XML/Nodes/Envelope/Security/Signature/SignatureValue.php +++ b/src/XML/Nodes/Envelope/Security/Signature/SignatureValue.php @@ -3,6 +3,7 @@ namespace Smartprax\Medidoc\XML\Nodes\Envelope\Security\Signature; use Sabre\Xml\Writer; +use Smartprax\Medidoc\Methods\Method; use Smartprax\Medidoc\XML\Nodes\Envelope\Security\Timestamp; use Smartprax\Medidoc\XML\Nodes\Node; use Smartprax\Medidoc\XML\XML_NS; @@ -10,6 +11,8 @@ class SignatureValue extends Node { + public function __construct(protected Method $method) {} + public function namespace(): ?XML_NS { return null; diff --git a/src/XML/Nodes/Envelope/Security/Signature/SignedInfo.php b/src/XML/Nodes/Envelope/Security/Signature/SignedInfo.php index b2513e1..171ab3a 100644 --- a/src/XML/Nodes/Envelope/Security/Signature/SignedInfo.php +++ b/src/XML/Nodes/Envelope/Security/Signature/SignedInfo.php @@ -2,12 +2,15 @@ namespace Smartprax\Medidoc\XML\Nodes\Envelope\Security\Signature; +use Smartprax\Medidoc\Methods\Method; use Smartprax\Medidoc\XML\Nodes\Envelope\Security\Signature\SignedInfo\Reference; use Smartprax\Medidoc\XML\XML_NS; class SignedInfo extends \Smartprax\Medidoc\XML\Nodes\Node { + public function __construct(protected Method $method) {} + public function namespace(): ?XML_NS { return null; diff --git a/src/XML/Nodes/Envelope/Security/Signature/SignedInfo/Reference.php b/src/XML/Nodes/Envelope/Security/Signature/SignedInfo/Reference.php index 2b8df69..6a86014 100644 --- a/src/XML/Nodes/Envelope/Security/Signature/SignedInfo/Reference.php +++ b/src/XML/Nodes/Envelope/Security/Signature/SignedInfo/Reference.php @@ -3,14 +3,16 @@ namespace Smartprax\Medidoc\XML\Nodes\Envelope\Security\Signature\SignedInfo; use Sabre\Xml\Writer; +use Smartprax\Medidoc\Methods\Method; use Smartprax\Medidoc\XML\Nodes\Envelope\Security\Signature\SignedInfo\Reference\DigestValue; -use Smartprax\Medidoc\XML\Nodes\Envelope\Security\Timestamp; use Smartprax\Medidoc\XML\Nodes\Node; use Smartprax\Medidoc\XML\XML_NS; class Reference extends Node { + public function __construct(protected Method $method) {} + public function namespace(): ?XML_NS { return null; diff --git a/src/XML/Nodes/Envelope/Security/Signature/SignedInfo/Reference/DigestValue.php b/src/XML/Nodes/Envelope/Security/Signature/SignedInfo/Reference/DigestValue.php index 5f37733..8b23feb 100644 --- a/src/XML/Nodes/Envelope/Security/Signature/SignedInfo/Reference/DigestValue.php +++ b/src/XML/Nodes/Envelope/Security/Signature/SignedInfo/Reference/DigestValue.php @@ -3,22 +3,20 @@ namespace Smartprax\Medidoc\XML\Nodes\Envelope\Security\Signature\SignedInfo\Reference; use Sabre\Xml\Writer; +use Smartprax\Medidoc\Methods\Method; use Smartprax\Medidoc\XML\Nodes\Envelope\Security\Timestamp; use Smartprax\Medidoc\XML\XML_NS; class DigestValue extends \Smartprax\Medidoc\XML\Nodes\Node { + public function __construct(protected Method $method) {} + public function namespace(): ?XML_NS { return null; } - public function attributes(): array - { - return []; - } - public function value(): string|array { $writer = new Writer(); diff --git a/src/XML/Nodes/Envelope/Security/Timestamp.php b/src/XML/Nodes/Envelope/Security/Timestamp.php index 319a764..7f4842f 100644 --- a/src/XML/Nodes/Envelope/Security/Timestamp.php +++ b/src/XML/Nodes/Envelope/Security/Timestamp.php @@ -2,12 +2,15 @@ namespace Smartprax\Medidoc\XML\Nodes\Envelope\Security; +use Smartprax\Medidoc\Methods\Method; use Smartprax\Medidoc\XML\Nodes\Node; use Smartprax\Medidoc\XML\XML_NS; class Timestamp extends Node { + public function __construct(protected Method $method) {} + public function namespace(): ?XML_NS { return XML_NS::wss_utility; @@ -24,12 +27,12 @@ public function value(): string|array { return [ [ - 'name' => XML_NS::wss_utility->node('Created'), + 'name' => XML_NS::wss_utility->clark('Created'), 'value' => $this->created(), ], [ - 'name' => XML_NS::wss_utility->node('Expires'), + 'name' => XML_NS::wss_utility->clark('Expires'), 'value' => $this->method->timestamp()->addSeconds(50)->toIso8601ZuluString(), ] diff --git a/src/XML/Nodes/Envelope/Security/UsernameToken.php b/src/XML/Nodes/Envelope/Security/UsernameToken.php new file mode 100644 index 0000000..9cb549f --- /dev/null +++ b/src/XML/Nodes/Envelope/Security/UsernameToken.php @@ -0,0 +1,47 @@ +attribute('Id') => '_0', + ]; + } + + public function value(): string|array + { + + return [ + + [ + 'name' => XML_NS::wss_secext->clark('Username'), + 'value' => \config('medidoc.gln'), + ], + + [ + 'name' => XML_NS::wss_secext->clark('Password'), + 'attributes' => [ + 'Type' => 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText' + ], + 'value' => \config('medidoc.encryption_key'), + ] + ]; + } +} diff --git a/src/XML/Nodes/Header.php b/src/XML/Nodes/Header.php new file mode 100644 index 0000000..fc08234 --- /dev/null +++ b/src/XML/Nodes/Header.php @@ -0,0 +1,14 @@ +getConstructor()?->getParameters() ?? []; + + // Pass the parameters to the (child) class constructor. + $instance = new static(...\array_slice($args, 0, \count($params))); + + // Set props if passed by name. + $instance->name = $args['name'] ?? null; + $instance->attributes = $args['attributes'] ?? []; + $instance->value = $args['value'] ?? []; + + return $instance; + } + + public function namespace() : ?XML_NS + { + return null; + } public function name() : string { - return Str::of(get_class($this)) + return $this->name ?? Str::of(get_class($this)) ->replace('\\', '/') ->basename(); } + public function value(): array|string|null + { + return $this->value; + } + + public function addChild(Node $child): static + { + $this->children[] = $child; + + return $this; + } + + public function attributes(): array + { + return $this->attributes; + } + public function xmlSerialize(Writer $writer): void { $writer->write([ - 'name' => $this->namespace() ? $this->namespace()->node($this->name()) : $this->name(), + 'name' => $this->namespace() ? $this->namespace()->clark($this->name()) : $this->name(), 'attributes' => $this->attributes(), - 'value' => $this->value(), + 'value' => match (true) { + \is_array($this->value()) => \array_filter([ + ...$this->value(), + ...$this->children, + ]), + default => $this->value(), + }, ]); } diff --git a/src/XML/XML_NS.php b/src/XML/XML_NS.php index d34643b..584d9a5 100644 --- a/src/XML/XML_NS.php +++ b/src/XML/XML_NS.php @@ -9,9 +9,10 @@ enum XML_NS : string case wss_utility = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'; case wss_secext = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'; case sc = 'http://schemas.xmlsoap.org/ws/2005/02/sc'; + case trust = 'http://schemas.xmlsoap.org/ws/2005/02/trust'; - public function node(string $name): string + public function clark(string $name): string { return '{' . $this->value . '}' . $name; }