File Coverage

lib/XML/Compile/WSS.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             # Copyrights 2011-2014 by [Mark Overmeer].
2             # For other contributors see ChangeLog.
3             # See the manual pages for details on the licensing terms.
4             # Pod stripped from pm file by OODoc 2.01.
5 1     1   1702 use warnings;
  1         2  
  1         45  
6 1     1   5 use strict;
  1         2  
  1         71  
7              
8             package XML::Compile::WSS;
9             our $VERSION = '1.12';
10              
11              
12 1     1   4 use Log::Report 'xml-compile-wss';
  1         2  
  1         10  
13              
14 1     1   357 use XML::Compile::WSS::Util qw/:wss11/;
  1         2  
  1         333  
15 1     1   529 use XML::Compile::Util qw/SCHEMA2001/;
  0            
  0            
16             use XML::Compile::Schema::BuiltInTypes qw/builtin_type_info/;
17              
18             use File::Basename qw/dirname/;
19             use Encode qw/encode/;
20             use MIME::Base64 qw/encode_base64/;
21             use POSIX qw/strftime/;
22             use Scalar::Util qw/weaken/;
23              
24             my %prefixes10 =
25             ( ds => DSIG_NS, wsse => WSSE_10, wsu => WSU_10
26             );
27              
28             my %prefixes11 =
29             ( ds => DSIG_NS, wsse => WSSE_10, wsu => WSU_10
30             , wss => WSS_11, xenc => XENC_NS
31             );
32              
33             my %versions =
34             ( '1.0' => { xsddir => 'wss10', prefixes => \%prefixes10 }
35             , '1.1' => { xsddir => 'wss11', prefixes => \%prefixes11 }
36             );
37              
38              
39             sub new(@)
40             { my $class = shift;
41             my $args = @_==1 ? shift : {@_};
42             my $self = (bless {}, $class)->init($args);
43             $self->prepare($args->{prepare} || 'ALL');
44             $self;
45             }
46              
47             sub init($)
48             { my ($self, $args) = @_;
49             my $version = $args->{wss_version} || $args->{version}
50             or error __x"explicit wss_version required";
51             trace "initializing wss $version";
52              
53             $version = '1.1'
54             if $version eq WSS11MODULE;
55              
56             $versions{$version}
57             or error __x"unknown wss version {v}, pick from {vs}"
58             , v => $version, vs => [keys %versions];
59             $self->{XCW_version} = $version;
60              
61             if(my $schema = $self->{XCW_schema} = $args->{schema})
62             { weaken $self->{XCW_schema};
63             $self->loadSchemas($schema, $version);
64             }
65              
66             $self;
67             }
68              
69             sub prepare($)
70             { my ($self, $how) = @_;
71             my $schema = $self->schema;
72              
73             my ($r, $w)
74             = $how eq 'ALL' ? (1, 1)
75             : $how eq 'READER' ? (1, 0)
76             : $how eq 'WRITER' ? (0, 1)
77             : $how eq 'NONE' ? (0, 0)
78             : panic $how;
79              
80             $self->prepareWriting($schema) if $w;
81             $self->prepareReading($schema) if $r;
82             $self;
83             }
84             sub prepareWriting($) { $_[0]->{XCW_prepare_w}++; $_[0] }
85             sub prepareReading($) { $_[0]->{XCW_prepare_r}++; $_[0] }
86              
87             #-----------
88              
89             sub version() {shift->{XCW_version}} # deprecated
90             sub wssVersion() {shift->{XCW_version}}
91             sub schema() {shift->{XCW_schema}}
92              
93             #-----------
94              
95             sub create($$)
96             { my $self = shift;
97             panic __x"WSS plugin {name} is not prepared for writing", name => ref $self
98             unless $self->{XCW_prepare_w};
99             $self;
100             }
101              
102              
103             sub check($)
104             { my $self = shift;
105             panic __x"WSS plugin {name} is not prepared for reading", name => ref $self
106             unless $self->{XCW_prepare_r};
107             $self;
108             }
109              
110             #-----------
111              
112             # wsu had "allow anything" date fields, not type dateTime
113             sub dateTime($)
114             { my ($self, $time) = @_;
115             return $time if !defined $time || ref $time;
116              
117             my $dateTime = builtin_type_info 'dateTime';
118             if($time !~ m/[^0-9.]/) { $time = $dateTime->{format}->($time) }
119             elsif($dateTime->{check}->($time)) {}
120             else {return $time}
121              
122             +{ _ => $time
123             , ValueType => SCHEMA2001.'/dateTime'
124             };
125             }
126              
127             #-----------
128              
129             sub loadSchemas($$)
130             { my ($thing, $schema, $version) = @_;
131             return if $schema->{XCW_wss_loaded}++;
132              
133             $schema->isa('XML::Compile::Cache')
134             or error __x"loadSchemas() requires a XML::Compile::Cache object";
135              
136             my $def = $versions{$version};
137             my $prefixes = $def->{prefixes};
138             $schema->addPrefixes($prefixes);
139              
140             my $rewrite = join ',', sort keys %$prefixes;
141             $schema->addKeyRewrite("PREFIXED($rewrite)");
142              
143             (my $xsddir = __FILE__) =~ s! \.pm$ !/$def->{xsddir}!x;
144             my @xsd = glob "$xsddir/*.xsd";
145              
146             trace "loading wss schemas $version";
147              
148             $schema->importDefinitions
149             ( \@xsd
150              
151             # Missing from wss-secext-1.1.xsd (schema BUG) Gladly, all
152             # provided schemas have element_form qualified.
153             , element_form_default => 'qualified'
154             );
155              
156             # Another schema bug; attribute wsu:Id not declared qualified
157             # Besides, ValueType is often used on timestamps, which are declared
158             # as free-format fields (@*!&$#!&^ design committees!)
159             my ($wsu10, $xsd) = (WSU_10, SCHEMA2001);
160             $schema->importDefinitions( <<__PATCH );
161            
162             xmlns="$xsd"
163             xmlns:wsu="$wsu10"
164             targetNamespace="$wsu10"
165             elementFormDefault="qualified"
166             attributeFormDefault="unqualified">
167            
168              
169            
170            
171            
172            
173            
174            
175            
176            
177              
178            
179             __PATCH
180              
181             $schema->allowUndeclared(1);
182             $schema->addCompileOptions(RW => mixed_elements => 'STRUCTURAL');
183             $schema->anyElement('ATTEMPT');
184             $schema;
185             }
186              
187              
188             sub writerHookWsuId($)
189             { my ($self, $type) = @_;
190              
191             my $wrapper = sub
192             { my ($doc, $values, $path, $tag, $r) = @_ ;
193              
194             # Remove $id first, to avoid $r complaining about unused
195             my $id = delete $values->{wsu_Id};
196             my $node = $r->($doc, $values);
197             if($id)
198             { $node->setNamespace(WSU_10, 'wsu', 0);
199             $node->setAttributeNS(WSU_10, 'Id' => $id);
200             }
201             $node;
202             };
203              
204             +{ type => $type, replace => $wrapper };
205             }
206              
207             #---------------------------
208              
209              
210             1;