#### # Functions implementing authx:* processing #### package Gestinanna::XSM::Authz; use strict; use base qw(Gestinanna::XSM); our $NS = 'http://ns.gestinanna.org/authz'; sub start_document { return "#initialize authz namespace\n"; } sub end_document { return ''; } sub comment { return ''; } sub processing_instruction { return ''; } sub characters { my ($e, $text) = @_; $e -> append_state('text', $text); return ''; } my %test_types = qw( lt < le <= gt > ge >= eq = ne != ); sub start_element { my ($e, $node) = @_; my ($tag, %attribs); $tag = $node->{Name}; foreach my $attrib (@{$node->{Attributes}}) { $attribs{$attrib->{Name}} = $attrib->{Value}; } # ... if ($tag eq 'assert') { # set up environment for and and and # worry about attributes, etc., when we close the tag $e -> push_state; $e -> reset_state($_) for qw( in-authz-and in-authz-or in-expression authz-and-level authz-or-level ); $e -> enter_state("authz-or-level"); return "do { my \@authz_or1; "; #} } elsif( $tag eq 'and' || $tag eq 'or' ) { my $in = $e -> state("in-authz-$tag"); $e -> enter_state("in-authz-$tag"); return '' if $in; # do nothing - flatten nested identical tags $e -> push_state; $e -> reset_state("in-authz-and") if $tag eq 'or'; $e -> reset_state("in-authz-or") if $tag eq 'and'; $e -> enter_state("authz-${tag}-level"); $in = $e -> state("authz-${tag}-level"); my $a = '@authz_' . $tag . $in; return "do { my $a; "; # } } elsif( $tag eq 'has' || $tag eq 'has-not' ) { my $and = $e -> state('in-authz-and') ? 'and' : 'or'; my $in = $e -> state("authz-${and}-level"); my $var = "\@authz_${and}${in}"; my $attr = $attribs{attribute}; $attr = "!$attr" if $tag eq 'has-not'; if($e -> state('in-expression')) { return "((push $var, " . $e -> makeSingleQuoted($attr) . "), undef)[1]" . $e -> semi; } return "push $var, " . $e -> makeSingleQuoted($attr) . $e -> semi; } else { warn("Unrecognised tag: $tag"); } return ''; } sub end_element { my ($e, $node) = @_; my($tag, %attribs); $tag = $node->{Name}; foreach my $attrib (@{$node->{Attributes}}) { $attribs{$attrib->{Name}} = $attrib->{Value}; } if($tag eq 'assert') { my $code = $e -> state('script'); $e -> pop_state; $e -> set_state(script => $code); my $select; $code = ''; $select = Gestinanna::XSM::compile_expr($e, $attribs{select}) if $attribs{select}; my($state, $type, $path, $attribute) = map { $e -> static_expr($_) } @attribs{qw(state type path attribute)}; if($select) { # base it on select and path # expect the objects to be POF objects $attribute = '*' unless defined $attribute && $attribute ne ''; $code = < has_access($attribute, \\\@authz_or1) } $select EOF } elsif(defined $path && defined $type) { $path .= "($path . '\@' . $attribute)" if defined $attribute && $attribute ne ''; #$path = $e -> makeSingleQuoted($path); #$type = $e -> makeSingleQuoted($type); my $factory = '$R -> factory'; $code = < {authz} -> has_attribute( [ eval { $factory -> {actor} -> object_type }, eval { $factory -> {actor} -> object_id } ], [ $type, $path ], \\\@authz_or1 ) EOF } if($code) { $code = "unless($code) { return ( ($attribs{state})[0] ); }"; } else { $code = "undef;"; } return "$code }" . $e -> semi; } elsif($tag eq 'and' || $tag eq 'or') { my $in = $e -> state("in-authz-$tag"); if($in > 1) { $e -> leave_state("in-authz-$tag"); return ''; } my($own_var, $next_var); my $other_tag = ($tag eq 'and') ? 'or' : 'and'; $own_var = '@authz_' . $tag . $e -> state("authz-${tag}-level"); $next_var = '@authz_' . $other_tag . $e -> state("authz-${other_tag}-level"); my $code = $e -> state('script'); $e -> pop_state; $e -> set_state(script => $code); if($e -> state('in-expression')) { return "((push $next_var, \\$own_var), undef)[1]" . $e -> semi; } return "push $next_var, \\$own_var;" . $e -> semi; } return ''; } sub xsm_has_access ($$$$) { my($sm, $type, $path, $attr) = @_; my $R = Gestinanna::Request -> instance; #return 0 unless $R -> factory -> {actor}; my $actor; if($R -> factory -> {actor}) { $actor = $sm -> {_cache}{authz}{actor} ||= [ $R -> factory -> {actor} -> object_type, $R -> factory -> {actor} -> object_id, ]; } else { $actor = [ 'user', 'guest' ]; } #warn "has_access($$actor[0], $$actor[1], $type, $path, $attr)\n"; return 0 unless defined $type && $type ne ''; return 0 unless defined $path && $path ne ''; return 0 unless defined $R -> factory -> {authz}; my $ret = $R -> factory -> {authz} -> has_attribute( $actor, [ $type, $path ], $attr ); #warn " returning $ret\n"; return $ret; } sub xsm_actor ($) { my($sm) = @_; my $R = Gestinanna::Request -> instance; my $actor; if($R -> factory -> {actor}) { $actor = $sm -> {_cache}{authz}{actor} ||= [ $R -> factory -> {actor} -> object_type, $R -> factory -> {actor} -> object_id, ]; } else { $actor = [ 'user', 'guest' ]; } return $actor; } 1;