From: <Cra...@nt...> - 2005-01-20 19:44:10
|
Author: CrawfordCurrie Date: 2005-01-20 11:42:37 -0800 (Thu, 20 Jan 2005) New Revision: 3555 Added: twiki/branches/DEVELOP/lib/TWiki/AccessControlException.pm twiki/branches/DEVELOP/lib/TWiki/Users.pm twiki/branches/DEVELOP/lib/TWiki/Users/ twiki/branches/DEVELOP/lib/TWiki/Users/HtPasswdUser.pm twiki/branches/DEVELOP/lib/TWiki/Users/NoPasswdUser.pm twiki/branches/DEVELOP/templates/oopsaccessdenied.tmpl Removed: twiki/branches/DEVELOP/lib/TWiki/User/ twiki/branches/DEVELOP/lib/TWiki/Users/HtPasswdUser.pm twiki/branches/DEVELOP/lib/TWiki/Users/NoPasswdUser.pm twiki/branches/DEVELOP/templates/oopsaccessview.tmpl Modified: twiki/branches/DEVELOP/lib/Error.pm twiki/branches/DEVELOP/lib/TWiki.pm twiki/branches/DEVELOP/lib/TWiki/Access.pm twiki/branches/DEVELOP/lib/TWiki/Attach.pm twiki/branches/DEVELOP/lib/TWiki/Data/DelimitedFile.pm twiki/branches/DEVELOP/lib/TWiki/Form.pm twiki/branches/DEVELOP/lib/TWiki/Func.pm twiki/branches/DEVELOP/lib/TWiki/Meta.pm twiki/branches/DEVELOP/lib/TWiki/Plugin.pm twiki/branches/DEVELOP/lib/TWiki/Prefs.pm twiki/branches/DEVELOP/lib/TWiki/Prefs/PrefsCache.pm twiki/branches/DEVELOP/lib/TWiki/Prefs/TopicPrefs.pm twiki/branches/DEVELOP/lib/TWiki/Render.pm twiki/branches/DEVELOP/lib/TWiki/Sandbox.pm twiki/branches/DEVELOP/lib/TWiki/Search.pm twiki/branches/DEVELOP/lib/TWiki/Store.pm twiki/branches/DEVELOP/lib/TWiki/Store/RcsFile.pm twiki/branches/DEVELOP/lib/TWiki/Store/RcsWrap.pm twiki/branches/DEVELOP/lib/TWiki/Templates.pm twiki/branches/DEVELOP/lib/TWiki/UI.pm twiki/branches/DEVELOP/lib/TWiki/UI/Changes.pm twiki/branches/DEVELOP/lib/TWiki/UI/Edit.pm twiki/branches/DEVELOP/lib/TWiki/UI/Manage.pm twiki/branches/DEVELOP/lib/TWiki/UI/Oops.pm twiki/branches/DEVELOP/lib/TWiki/UI/OopsException.pm twiki/branches/DEVELOP/lib/TWiki/UI/Preview.pm twiki/branches/DEVELOP/lib/TWiki/UI/RDiff.pm twiki/branches/DEVELOP/lib/TWiki/UI/Register.pm twiki/branches/DEVELOP/lib/TWiki/UI/Save.pm twiki/branches/DEVELOP/lib/TWiki/UI/Statistics.pm twiki/branches/DEVELOP/lib/TWiki/UI/Upload.pm twiki/branches/DEVELOP/lib/TWiki/UI/View.pm twiki/branches/DEVELOP/lib/TWiki/User.pm twiki/branches/DEVELOP/templates/changes.tmpl twiki/branches/DEVELOP/templates/search.pattern.tmpl twiki/branches/DEVELOP/templates/search.tmpl twiki/branches/DEVELOP/templates/searchbookview.pattern.tmpl twiki/branches/DEVELOP/templates/searchbookview.tmpl twiki/branches/DEVELOP/templates/searchrenameview.pattern.tmpl twiki/branches/DEVELOP/templates/searchrenameview.tmpl twiki/branches/DEVELOP/test/unit/RegisterTests.pm twiki/branches/DEVELOP/test/unit/StoreTests.pm Log: UserObject: support for user object. See topic for full details Modified: twiki/branches/DEVELOP/lib/Error.pm =================================================================== --- twiki/branches/DEVELOP/lib/Error.pm 2005-01-20 16:38:24 UTC (rev 3554) +++ twiki/branches/DEVELOP/lib/Error.pm 2005-01-20 19:42:37 UTC (rev 3555) @@ -385,7 +385,6 @@ } 1; }; - $err = defined($Error::THROWN) ? $Error::THROWN : $@ unless $ok; }; Modified: twiki/branches/DEVELOP/lib/TWiki/Access.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Access.pm 2005-01-20 16:38:24 UTC (rev 3554) +++ twiki/branches/DEVELOP/lib/TWiki/Access.pm 2005-01-20 19:42:37 UTC (rev 3555) @@ -92,35 +92,35 @@ ---++ checkAccessPermission( $action, $user, $text, $topic, $web ) ==> $ok | Description: | Check if user is allowed to access topic | | Parameter: =$action= | "VIEW", "CHANGE", "CREATE", etc. | -| Parameter: =$user= | Remote WikiName, e.g. "Main.PeterThoeny" | +| Parameter: =$user= | User object | | Parameter: =$text= | If empty: Read "$theWebName.$theTopicName" to check permissions | | Parameter: =$topic= | Topic name to check, e.g. "SomeTopic" | | Parameter: =$web= | Web, e.g. "Know" | -| Return: =$ok= | 1 if OK to access, 0 if no permission | +| Return: 1 if access is OK | =cut sub checkAccessPermission { - my( $this, $theAccessType, $theUserName, + my( $this, $theAccessType, $user, $theTopicText, $theTopicName, $theWebName ) = @_; ASSERT(ref($this) eq "TWiki::Access") if DEBUG; + ASSERT(ref($user) eq "TWiki::User") if DEBUG; # super admin is always allowed - if ( $TWiki::doSuperAdminGroup && $TWiki::superAdminGroup ) { - if ( $this->userIsInGroup( $theUserName, $TWiki::superAdminGroup )) { - return 1; - } - } + return 1 if $user->isAdmin(); $theAccessType = uc( $theAccessType ); # upper case if( ! $theWebName ) { $theWebName = $this->{session}->{webName}; } + if( ! $theTopicText ) { # text not supplied as parameter, so read topic. The # read is "Raw" just to hint to store that we want the # data _fast_. - $theTopicText = $this->store()->readTopicRaw( $this->{session}->{wikiUserName}, $theWebName, $theTopicName, undef, 1 ); + $theTopicText = $this->store()->readTopicRaw( undef, $theWebName, + $theTopicName, + undef ); } my $allowText; @@ -142,21 +142,19 @@ } } + my $check; # DENYTOPIC overrides DENYWEB, even if it is empty unless( defined( $denyText )) { $denyText = - $this->prefs()->getPreferencesValue( "DENYWEB$theAccessType", - $theWebName ); + $this->prefs()->getPreferencesValue( "DENYWEB$theAccessType", $theWebName ); } if( defined( $denyText )) { - my %deny = $this->_parseUserList( $denyText, 1 ); - return 0 if $deny{$theUserName}; + return 0 if( $user->isInList( $denyText )); } if( defined( $allowText )) { - my %allow = $this->_parseUserList( $allowText, 1 ); - return 0 unless $allow{$theUserName}; + return 0 unless( $user->isInList( $allowText )); } else { # ALLOWTOPIC overrides ALLOWWEB, even if it is empty $allowText = @@ -164,174 +162,11 @@ $theWebName ); if( defined( $allowText ) && $allowText =~ /\S/ ) { - my %allow = $this->_parseUserList( $allowText, 1 ); - return 0 unless $allow{$theUserName}; + return 0 unless $user->isInList( $allowText ); } } return 1; } -# get a list of groups defined in this TWiki -sub _getListOfGroups { - my $this = shift; - - my @list; - $this->search()->searchWeb - ( - _callback => \&_collateGroups, - _cbdata => \@list, - inline => 1, - search => "Set GROUP =", - web => "all", - topic => "*Group", - type => "regex", - nosummary => "on", - nosearch => "on", - noheader => "on", - nototal => "on", - noempty => "on", - format => "\$web.\$topic", - separator => "", - ); - - return @list; -} - -# callback for search function to collate results -sub _collateGroups { - my $ref = shift; - my $group = shift; - push( @$ref, $group ) if $group; -} - -# ========================= -=pod - ----++ getGroupsUserIsIn( $user ) ==> @listOfGroups -| Description: | get a list of groups a user is in | -| Parameter: =$user= | Remote WikiName, e.g. "Main.PeterThoeny" | -| Return: =@listOfGroups= | list os all the WikiNames for a group | - -=cut - -sub getGroupsUserIsIn { - my( $this, $theUserName ) = @_; - ASSERT(ref($this) eq "TWiki::Access") if DEBUG; - - my $userTopic = _getWebTopicName( $TWiki::mainWebname, $theUserName ); - - my @grpMembers = (); - foreach my $group ( $this->_getListOfGroups() ) { - if ( $this->userIsInGroup( $userTopic, $group )) { - push ( @grpMembers, $group ); - } - } - - return @grpMembers; -} - -# ========================= -=pod - ----++ userIsInGroup( $user, $group ) ==> $ok -Check if user is a member of a group. If a topic which is -not a group is specified, checks if it is the users topic. -| Parameter: =$user= | Remote WikiName, e.g. "Main.PeterThoeny" | -| Parameter: =$group= | Group name, e.g. "Main.EngineeringGroup" | -| Return: =$ok= | 1 user is in group, 0 if not | - -=cut - -sub userIsInGroup { - my( $this, $theUserName, $theGroupTopicName ) = @_; - ASSERT(ref($this) eq "TWiki::Access") if DEBUG; - - my $usrTopic = _getWebTopicName( $TWiki::mainWebname, $theUserName ); - my $grpTopic = _getWebTopicName( $TWiki::mainWebname, $theGroupTopicName ); - - if( $grpTopic !~ /.*Group$/ ) { - # not a group, so compare user to user - return ( $grpTopic eq $usrTopic ); - } - unless( $this->{GROUPS}{$grpTopic} ) { - $this->_getUsersOfGroup( $grpTopic ); - } - - return $this->{GROUPS}{$grpTopic}{$usrTopic}; -} - -# Expand groups recursively, returning a list of the leaf-level -# members of the group -# | =$group= | Group topic name, e.g. "Main.EngineeringGroup" | -sub _getUsersOfGroup { - my( $this, $theGroupTopicName, $processedGroups ) = @_; - - # extract web and topic name - my $topic = $theGroupTopicName; - my $web = $TWiki::mainWebname; - $topic =~ /^([^\.]*)\.(.*)$/; - if( $2 ) { - $web = $1; - $topic = $2; - } - my $grpTopic = "$web.$topic"; - - if( $topic !~ /.*Group$/ ) { - # return user, is not a group - return ( $grpTopic ); - } - - unless( defined( $this->{GROUPS}{$grpTopic} )) { - my $text = $this->store()->readTopicRaw( $this->{session}->{wikiUserName}, - $web, $topic, undef, 1 ); - - foreach( split( /\n/, $text ) ) { - if( /^\s+\*\sSet\sGROUP\s*\=\s*(.+)$/ ) { - # Note: if there are multiple GROUP assignments in the - # topic, the last will be taken. - %{$this->{GROUPS}{$grpTopic}} = $this->_parseUserList( $1, 1 ); - } - } - } - - return keys %{$this->{GROUPS}{$grpTopic}}; -} - -# Build a Web.Topic name, -# SMELL: this is a hack, isn't it? What should really be going on here? -sub _getWebTopicName { - my( $theWebName, $theTopicName ) = @_; - $theTopicName =~ s/%MAINWEB%/$theWebName/go; - $theTopicName =~ s/%TWIKIWEB%/$theWebName/go; - $theWebName = $TWiki::mainWebname unless $theWebName; - if( $theTopicName !~ /[\.]/ ) { - $theTopicName = "$theWebName\.$theTopicName"; - } - return $theTopicName; -} - -# Get a hash indexed by the users in a list. If expand is -# true, recursively expand groups defined in the list to create -# a flat has of users. -sub _parseUserList { - my( $this, $theItems, $expand ) = @_; - - # comma delimited list of users or groups - # i.e.: "%MAINWEB%.UserA, UserB, Main.UserC # something else" - $theItems =~ s/(<[^>]*>)//go; # Remove HTML tags - # TODO: i18n fix for user name - $theItems =~ s/\s*([a-zA-Z0-9_\.\,\s\%]*)\s*(.*)/$1/go; # Limit list - my %list; - foreach( split( /[\,\s]+/, $theItems )) { - my $e = _getWebTopicName( $TWiki::mainWebname, $_ ); - if ( $expand ) { - map { $list{$_} = 1; } $this->_getUsersOfGroup( $e ); - } else { - $list{$e} = 1; - } - } - return %list; -} - 1; Added: twiki/branches/DEVELOP/lib/TWiki/AccessControlException.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/AccessControlException.pm 2005-01-20 16:38:24 UTC (rev 3554) +++ twiki/branches/DEVELOP/lib/TWiki/AccessControlException.pm 2005-01-20 19:42:37 UTC (rev 3555) @@ -0,0 +1,48 @@ +# TWiki Collaboration Platform, http://TWiki.org/ +# +# Copyright (C) 2005 Crawford Currie http://c-dot.co.uk +# +# For licensing info read license.txt file in the TWiki root. +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details, published at +# http://www.gnu.org/copyleft/gpl.html + +=pod twiki + +---+ package TWiki::AccessControlException + +Exception used raise an access control violation. + +=cut + +package TWiki::AccessControlException; + +use strict; +use Error; + +@TWiki::AccessControlException::ISA = qw(Error); + +sub new { + my ( $class, $mode, $user, $web, $topic ) = @_; + + return $class->SUPER::new( + -web => $web, + -topic => $topic, + -user => $user->wikiName(), + -mode => $mode, + ); +} + +sub stringify { + my $self = shift; + return "AccessControlException: $self->{-mode} access to $self->{-web}.$self->{-topic} denied for $self->{-user}"; +} + +1; Modified: twiki/branches/DEVELOP/lib/TWiki/Attach.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Attach.pm 2005-01-20 16:38:24 UTC (rev 3554) +++ twiki/branches/DEVELOP/lib/TWiki/Attach.pm 2005-01-20 19:42:37 UTC (rev 3555) @@ -144,14 +144,14 @@ my $rows =""; for( my $rev = $latestRev; $rev >= 1; $rev-- ) { - my( $date, $userName, $minorRev, $comment ) = + my( $date, $user, $minorRev, $comment ) = $this->store()->getRevisionInfo( $web, $topic, $rev, $attrs{name} ); $rows .= $this->_formatRow( $web, $topic, { name => $attrs{name}, version => $rev, date => $date, - user => $userName, + user => $user->login(), comment => $comment, attr => $attrs{attr}, size => $attrs{size} @@ -238,7 +238,10 @@ return TWiki::formatTime( $info->{date} ); } elsif ( $attr eq "USER" ) { - return $this->users()->userToWikiName( $info->{user} ); + my $s = $info->{user}; + my $u = $this->users()->findUser( $s ); + $s = $u->webDotWikiName() if $u; + return $s } else { return "\0A_$attr\0"; @@ -247,7 +250,8 @@ =pod ----++ sub getAttachmentLink( $web, $topic, $name, $meta ) +---++ sub getAttachmentLink( $user, $web, $topic, $name, $meta ) +| =$user= | User doing the reading | | =$web= | Name of the web | | =$topic= | Name of the topic | | =$name= | Name of the attachment | @@ -257,7 +261,7 @@ =cut sub getAttachmentLink { - my ( $this, $web, $topic, $attName, $meta ) = @_; + my ( $this, $user, $web, $topic, $attName, $meta ) = @_; ASSERT(ref($this) eq "TWiki::Attach") if DEBUG; my %att = $meta->findOne( "FILEATTACHMENT", $attName ); @@ -276,7 +280,7 @@ # downloaded. When you upload an image to TWiki and checkmark # the link checkbox, TWiki will generate the width and height # img parameters, speeding up the page rendering. - my $stream = $this->store()->getAttachmentStream( $web, $topic, $attName ); + my $stream = $this->store()->getAttachmentStream( $user, $web, $topic, $attName ); my( $nx, $ny ) = &_imgsize( $stream, $attName ); if( ( $nx > 0 ) && ( $ny > 0 ) ) { @@ -561,7 +565,8 @@ if( ! $fileUser ) { $fileUser = ""; } else { - $fileUser = $this->users()->wikiToUserName( $fileUser ); + my $u = $this->users()->findUser( $fileUser ); + $fileUser = $u->login() if $u; } $fileUser =~ s/ //go; ( $before, $fileComment, $after ) = split( /<(?:\/)*TwkFileComment>/, $atext ); @@ -667,7 +672,8 @@ $date = TWiki::Store::RcsFile::revDate2EpSecs( $date ); } $att->{"date"} = $date; - $att->{"user"} = $this->users()->wikiToUserName( $att->{"user"} ); + my $u = $this->users()->findUser( $att->{user} ); + $att->{user} = $u->login() if $u; } } Modified: twiki/branches/DEVELOP/lib/TWiki/Data/DelimitedFile.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Data/DelimitedFile.pm 2005-01-20 16:38:24 UTC (rev 3554) +++ twiki/branches/DEVELOP/lib/TWiki/Data/DelimitedFile.pm 2005-01-20 19:42:37 UTC (rev 3555) @@ -1,6 +1,7 @@ package TWiki::Data::DelimitedFile; use Data::Dumper; +use Error qw( :try ); sub read { my (%settings) = @_; Modified: twiki/branches/DEVELOP/lib/TWiki/Form.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Form.pm 2005-01-20 16:38:24 UTC (rev 3554) +++ twiki/branches/DEVELOP/lib/TWiki/Form.pm 2005-01-20 19:42:37 UTC (rev 3555) @@ -185,7 +185,7 @@ # Read topic that defines the form if( $this->store()->topicExists( $webName, $form ) ) { my( $meta, $text ) = - $this->store()->readTopic( $this->{session}->{wikiUserName}, $webName, $form, undef, 0 ); + $this->store()->readTopic( $this->{session}->{user}, $webName, $form, undef ); @fieldDefs = $this->_parseFormDefinition( $text ); } else { # FIXME - do what if there is an error? @@ -204,7 +204,7 @@ if( ( ! @posValues ) && $this->store()->topicExists( $webName, $name ) ) { my( $meta, $text ) = - $this->store()->readTopic( $this->{session}->{wikiUserName}, $webName, $name, undef, 0 ); + $this->store()->readTopic( $this->{session}->{user}, $webName, $name, undef ); @posValues = getPossibleFieldValues( $text ); if( ! $type ) { $type = "select"; #FIXME keep? @@ -570,7 +570,7 @@ my @forms = split( /\s*,\s*/, $listForms ); unshift @forms, ""; my( $metat, $tmp ) = - $this->store()->readTopic( $this->{session}->{wikiUserName}, $theWeb, $theTopic, undef, 0 ); + $this->store()->readTopic( $this->{session}->{user}, $theWeb, $theTopic, undef ); my $formName = $q->param( 'formtemplate' ) || ""; if( ! $formName ) { my %form = $metat->findOne( "FORM" ); Modified: twiki/branches/DEVELOP/lib/TWiki/Func.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Func.pm 2005-01-20 16:38:24 UTC (rev 3554) +++ twiki/branches/DEVELOP/lib/TWiki/Func.pm 2005-01-20 19:42:37 UTC (rev 3555) @@ -43,6 +43,7 @@ package TWiki::Func; use strict; +use Error qw( :try ); # ========================= =pod @@ -467,7 +468,7 @@ ---+++ getDefaultUserName( ) ==> $loginName -| Description: | Get default user name as defined in TWiki.cfg's =$defaultUserName= | +| Description: | Get default user name as defined in TWiki.cfg =$defaultUserName= | | Return: =$loginName= | Default user name, e.g. ="guest"= | | Since: | TWiki::Plugins::VERSION 1.000 (7 Dec 2002) | @@ -491,7 +492,7 @@ # ------------------------- sub getWikiName { - return $TWiki::Plugins::SESSION->{users}->userToWikiName( $TWiki::Plugins::SESSION->{userName}, 1 ); + return $TWiki::Plugins::SESSION->{user}->wikiName(); } # ========================= @@ -507,7 +508,7 @@ # ------------------------- sub getWikiUserName { - return $TWiki::Plugins::SESSION->{users}->userToWikiName( $TWiki::Plugins::SESSION->{userName} ); + return $TWiki::Plugins::SESSION->{user}->webDotWikiName(); } # ========================= @@ -524,8 +525,10 @@ # ------------------------- sub wikiToUserName { -# my( $wiki ) = @_; - return $TWiki::Plugins::SESSION->{users}->wikiToUserName( @_ ); + my( $wiki ) = @_; + my $user = $TWiki::Plugins::SESSION->{users}->findUser( $wiki ); + return $wiki unless $user; + return $user->login(); } # ========================= @@ -543,8 +546,11 @@ # ------------------------- sub userToWikiName { -# my( $loginName, $dontAddWeb ) = @_; - return $TWiki::Plugins::SESSION->{users}->userToWikiName( @_ ); + my( $login, $dontAddWeb ) = @_; + my $user = $TWiki::Plugins::SESSION->{users}->findUser( $login ); + return "" unless $user; + return $user->wikiName() if $dontAddWeb; + return $user->webDotWikiName(); } # ========================= @@ -560,7 +566,7 @@ # ------------------------- sub isGuest { - return ( $TWiki::Plugins::SESSION->{userName} eq $TWiki::defaultUserName ); + return $TWiki::Plugins::SESSION->{user}->isDefaultUser(); } # ========================= @@ -714,15 +720,17 @@ { my( $web, $topic, $rev, $ignorePermissions ) = @_; - $ignorePermissions = 0 unless defined( $ignorePermissions ); + my $user; + $user = $TWiki::Plugins::SESSION->{user} + unless defined( $ignorePermissions ); - my $text = - $TWiki::Plugins::SESSION->{store}->readTopicRaw( $TWiki::Plugins::SESSION->{wikiUserName}, $web, $topic, $rev, - $ignorePermissions ); - - # FIXME: The following breaks if spec of readTopicRaw() changes - if( $text =~ /^No permission to read topic/ ) { - $text = $TWiki::Plugins::SESSION->getOopsUrl( $web, $topic, "oopsaccessview" ); + try { + my $text = + $TWiki::Plugins::SESSION->{store}->readTopicRaw + ( $user, $web, $topic, $rev ); + } catch TWiki::AccessControlException with { + $text = $TWiki::Plugins::SESSION->getOopsUrl + ($web, $topic, "oopsaccessdenied" ); } return $text; } @@ -767,7 +775,7 @@ # check access permission unless( $ignorePermissions || $TWiki::Plugins::SESSION->{security}->checkAccessPermission( "change", - $TWiki::Plugins::SESSION->{wikiUserName}, "", + $TWiki::Plugins::SESSION->{user}, "", $topic, $web ) ) { return $TWiki::Plugins::SESSION->getOopsUrl( $web, $topic, "oopsaccesschange" ); @@ -779,13 +787,13 @@ # extract meta data and merge old attachment meta data my $meta = $TWiki::Plugins::SESSION->{store}->extractMetaData( $web, $topic, \$text ); my( $oldMeta, $oldText ) = - $TWiki::Plugins::SESSION->{store}->readTopic( $TWiki::Plugins::SESSION->{wikiUserName}, $web, $topic, undef, 1 ); + $TWiki::Plugins::SESSION->{store}->readTopic( undef, $web, $topic, undef ); $meta->copyFrom( $oldMeta, "FILEATTACHMENT" ); # save topic my $error = $TWiki::Plugins::SESSION->{store}->saveTopic - ( $TWiki::Plugins::SESSION->{userName}, $web, $topic, $text, $meta, + ( $TWiki::Plugins::SESSION->{user}, $web, $topic, $text, $meta, { notify => $dontNotify } ); return $TWiki::Plugins::SESSION->getOopsUrl( $web, $topic, "oopssaveerr", $error ) if( $error ); return ""; @@ -1004,7 +1012,7 @@ { my( $web, $topic ) = @_; - return $TWiki::Plugins::SESSION->{store}->readTopic( $TWiki::Plugins::SESSION->{wikiUserName}, $web, $topic, undef, 0 ); + return $TWiki::Plugins::SESSION->{store}->readTopic( $TWiki::Plugins::SESSION->{user}, $web, $topic, undef, 0 ); } # ========================= Modified: twiki/branches/DEVELOP/lib/TWiki/Meta.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Meta.pm 2005-01-20 16:38:24 UTC (rev 3554) +++ twiki/branches/DEVELOP/lib/TWiki/Meta.pm 2005-01-20 19:42:37 UTC (rev 3555) @@ -77,7 +77,6 @@ # fields will be assumed to be meta-data. $self->{_session} = $session; -#$ENV{'TWIKI_ASSERTS'} = 1; throw Error::Simple("ASSERT: no web") unless $web; throw Error::Simple("ASSERT: no topic") unless $topic; @@ -88,6 +87,7 @@ } sub store { my $this = shift; return $this->{_session}->{store}; } +sub users { my $this = shift; return $this->{_session}->{users}; } =pod @@ -308,7 +308,7 @@ ASSERT(ref($self) eq "TWiki::Meta") if DEBUG; my $time = $options->{forcedate} || time(); - my $user = $options->{forceuser} || $self->{_session}->{userName}; + my $user = $options->{forceuser} || $self->{_session}->{user}; $rev = 1 unless $rev; @@ -318,7 +318,7 @@ # save with them so old code can read these topics version => "1.$rev", date => $time, - author => $user, + author => $user->wikiName(), format => $formatVersion ); $self->put( "TOPICINFO", @args ); @@ -346,7 +346,7 @@ my( $date, $author, $rev, $comment ); if( %topicinfo ) { $date = $topicinfo{"date"} ; - $author = $topicinfo{"author"}; + $author = $self->users()->findUser($topicinfo{"author"}); $rev = $topicinfo{"version"}; $rev =~ s/^\d+\.//; $comment = ""; Modified: twiki/branches/DEVELOP/lib/TWiki/Plugin.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Plugin.pm 2005-01-20 16:38:24 UTC (rev 3554) +++ twiki/branches/DEVELOP/lib/TWiki/Plugin.pm 2005-01-20 19:42:37 UTC (rev 3555) @@ -165,7 +165,7 @@ no strict 'refs'; my $status = &$sub( $TWiki::Plugins::SESSION->{topicName}, $TWiki::Plugins::SESSION->{webName}, - $TWiki::Plugins::SESSION->{userName}, + $TWiki::Plugins::SESSION->{user}->login(), $this->{web} ); use strict 'refs'; Modified: twiki/branches/DEVELOP/lib/TWiki/Prefs/PrefsCache.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Prefs/PrefsCache.pm 2005-01-20 16:38:24 UTC (rev 3554) +++ twiki/branches/DEVELOP/lib/TWiki/Prefs/PrefsCache.pm 2005-01-20 19:42:37 UTC (rev 3555) @@ -45,15 +45,21 @@ | Parameter: =$parent= | Prefs object from which to inherit higher-level settings. | | Parameter: =@target= | What this object stores preferences for, see notes. | -*Notes:* =$type= should be one of "global", "web", "request", or "copy". If the -type is "global", no parent or target should be specified; the object will -cache sitewide preferences. If the type is "web", =$parent= should hold global -preferences, and @target should contain only the web's name. If the type is -"request", then $parent should be a "web" preferences object for the current -web, and =@target= should be( $topicName, $userName ). $userName should be -just the WikiName, with no web specifier. If the type is "copy", the result is -a simple copy of =$parent=; no =@target= is needed. +*Notes:* =$type= should be one of "global", "web", "request", or "copy". +If the type is "global", no parent or target should be specified; the +object will cache sitewide preferences. + +If the type is "web", =$parent= should hold global +preferences, and @target should contain only the web's name. + +If the type is "request", then $parent should be a "web" preferences object +for the current web, and =@target= should be( $topicName, $user ). +$user should be the user object. + +If the type is "copy", the result is a simple copy of =$parent=; no +=@target= is needed. + Call like this: =$mainWebPrefs = Prefs->new("web", "Main");= =cut @@ -82,6 +88,7 @@ if( $theType eq "request" ) { $self->{topic} = $theTarget[0]; $self->{user} = $theTarget[1]; + ASSERT(ref($self->{user}) eq "TWiki::User") if DEBUG; } $self->loadPrefs( 1 ); @@ -141,7 +148,7 @@ "", $allowCache); } $self->loadPrefsFromTopic( $TWiki::mainWebname, - $self->{user}, + $self->{user}->wikiName(), "", $allowCache ); if( $topicPrefsSetting && $topicPrefsOverride ) { # topic prefs override user prefs Modified: twiki/branches/DEVELOP/lib/TWiki/Prefs/TopicPrefs.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Prefs/TopicPrefs.pm 2005-01-20 16:38:24 UTC (rev 3554) +++ twiki/branches/DEVELOP/lib/TWiki/Prefs/TopicPrefs.pm 2005-01-20 19:42:37 UTC (rev 3555) @@ -76,9 +76,9 @@ return unless $self->store()->topicExists( $theWeb, $theTopic ); my( $meta, $text ) = - $self->store()->readTopic( $self->{session}->{wikiUserName}, + $self->store()->readTopic( undef, $theWeb, $theTopic, - undef, 1 ); + undef ); my $parser = new TWiki::Prefs::Parser(); $parser->parseText( $text, $self ); Modified: twiki/branches/DEVELOP/lib/TWiki/Prefs.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Prefs.pm 2005-01-20 16:38:24 UTC (rev 3554) +++ twiki/branches/DEVELOP/lib/TWiki/Prefs.pm 2005-01-20 19:42:37 UTC (rev 3555) @@ -63,27 +63,22 @@ =pod ----+++ sub initializeUser( $wikiname, $usertopic ) +---+++ sub initializeUser( $user, $usertopic ) -STATIC Reads preferences from the user's personal topic. The parameter -is the topic to read user-level preferences from (Generally -"Main.CurrentUserName"). +STATIC Reads preferences from the user's personal topic. =cut sub initializeUser { - my( $this, $wikiname, $topic ) = @_; + my( $this, $user, $topic ) = @_; ASSERT(ref($this) eq "TWiki::Prefs") if DEBUG; + ASSERT(ref($user) eq "TWiki::User") if DEBUG; - $wikiname = "$TWiki::mainWebname.$TWiki::defaultWikiName" unless $wikiname; - - if( $wikiname =~ /^(.*)\.(.*)$/ ) { - my $webPrefs = $this->{WEBS}{$this->{WEBNAME}}; - $this->{REQUEST} = - new TWiki::Prefs::PrefsCache($this->{session}, - "request", $webPrefs, - $topic, $2); - } + my $webPrefs = $this->{WEBS}{$this->{WEBNAME}}; + $this->{REQUEST} = + new TWiki::Prefs::PrefsCache($this->{session}, + "request", $webPrefs, + $topic, $user); } =pod Modified: twiki/branches/DEVELOP/lib/TWiki/Render.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Render.pm 2005-01-20 16:38:24 UTC (rev 3554) +++ twiki/branches/DEVELOP/lib/TWiki/Render.pm 2005-01-20 19:42:37 UTC (rev 3555) @@ -156,7 +156,8 @@ my $toWeb = $1; my $toTopic = $2; my $by = $moved{"by"}; - $by = $this->users()->userToWikiName( $by ); + my $u = $this->users()->findUser( $by ); + $by = $u->webDotWikiName() if $u; my $date = $moved{"date"}; $date = TWiki::formatTime( $date, "", "gmtime" ); @@ -387,11 +388,11 @@ $text =~ s/\$rev/1.$rev/g; $text =~ s/\$date/TWiki::formatTime( $date )/ge; $text =~ s/\$username/<nop>$user/g; # "jsmith" - $text =~ s/\$wikiname/"<nop>" . $this->users()->userToWikiName( $user, 1 )/ge; # "JohnSmith" - $text =~ s/\$wikiusername/"<nop>" . $this->users()->userToWikiName( $user )/ge; # "Main.JohnSmith" + $text =~ s/\$wikiname/"<nop>" . $user->wikiName()/ge; # "JohnSmith" + $text =~ s/\$wikiusername/"<nop>" . $user->webDotWikiName()/ge; # "Main.JohnSmith" if( $text =~ /\$summary/ ) { my $summary = $this->store()->readTopicRaw - ( $this->{session}->{wikiUserName}, $theWeb, $theTopic, undef, 1 ); + ( undef, $theWeb, $theTopic, undef ); $summary = $this->makeTopicSummary( $summary, $theTopic, $theWeb ); $summary =~ s/[\"\']/<nop>/g; # remove quotes (not allowed in title attribute) $text =~ s/\$summary/$summary/g; @@ -660,7 +661,7 @@ unless ( $meta ) { my $dummyText; ( $meta, $dummyText ) = - $this->store()->readTopic( $this->{session}->{wikiUserName}, $formWeb, $formTopic, undef, 0 ); + $this->store()->readTopic( $this->{session}->{user}, $formWeb, $formTopic, undef ); $this->{ffCache}{"$formWeb.$formTopic"} = $meta; } Modified: twiki/branches/DEVELOP/lib/TWiki/Sandbox.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Sandbox.pm 2005-01-20 16:38:24 UTC (rev 3554) +++ twiki/branches/DEVELOP/lib/TWiki/Sandbox.pm 2005-01-20 19:42:37 UTC (rev 3555) @@ -233,6 +233,7 @@ if ( $param =~ /^([0-9A-Za-z.+_\-]{0,30})$/ ) { push @targs, $1; } else { +ASSERT(0); throw Error::Simple( "invalid string argument" ); } } elsif ($flag =~ /D/) { Modified: twiki/branches/DEVELOP/lib/TWiki/Search.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Search.pm 2005-01-20 16:38:24 UTC (rev 3554) +++ twiki/branches/DEVELOP/lib/TWiki/Search.pm 2005-01-20 19:42:37 UTC (rev 3555) @@ -771,9 +771,9 @@ $out =~ s/\$date/$revDate/gos; $out =~ s/\$isodate/&revDate2ISO($revDate)/geos; $out =~ s/\$rev/$revNum/gos; - $out =~ s/\$wikiusername/$revUser/gos; - $out =~ s/\$wikiname/wikiName($revUser)/geos; - $out =~ s/\$username/$this->users()->wikiToUserName($revUser)/geos; + $out =~ s/\$wikiusername/$revUser->webDotWikiName()/geos; + $out =~ s/\$wikiname/$revUser->wikiName()/geos; + $out =~ s/\$username/$revUser->login()/geos; my $r1info = {}; $out =~ s/\$createdate/$this->_getRev1Info( $web, $topic, "date", $r1info )/geos; $out =~ s/\$createusername/$this->_getRev1Info( $web, $topic, "username", $r1info )/geos; @@ -793,7 +793,6 @@ } $out =~ s/%WEB%/$web/go; $out =~ s/%TOPICNAME%/$topic/go; - $out =~ s/%LOCKED%//o; $out =~ s/%TIME%/$revDate/o; my $revNumText; if( $revNum > 1 ) { @@ -815,11 +814,12 @@ if( $doRenameView ) { # Permission check done below, so force this read to succeed with "internal" parameter - my $rawText = $this->store()->readTopicRaw( $this->{session}->{wikiUserName}, $web, $topic, undef, 1 ); + my $rawText = $this->store()->readTopicRaw + ( undef, $web, $topic, undef ); my $changeable = ""; my $changeAccessOK = $this->security()->checkAccessPermission( "change", - $this->{session}->{wikiUserName}, + $this->{session}->{user}, $text, $topic, $web ); if( ! $changeAccessOK ) { @@ -1060,15 +1060,16 @@ $info->{text} = $text; $info->{meta} = $meta; - my ( $revdate, $revuser, $revnum ) = $meta->getRevisionInfo( $web, $topic ); - $info->{editby} = $this->users()->userToWikiName( $revuser ); + my ( $revdate, $revuser, $revnum ) = + $meta->getRevisionInfo( $web, $topic ); + $info->{editby} = $revuser ? $revuser->wikiName() : ""; $info->{modified} = $revdate; $info->{revNum} = $revnum; $info->{allowView} = $this->security()-> checkAccessPermission( "view", - $this->{session}->{wikiUserName}, + $this->{session}->{user}, $text, $topic, $web ); @@ -1094,7 +1095,7 @@ unless( defined $text ) { ( $meta, $text ) = - $this->store()->readTopic( $this->{session}->{wikiUserName}, $web, $topic, undef, 1 ); + $this->store()->readTopic( undef, $web, $topic, undef ); $text =~ s/%WEB%/$web/gos; $text =~ s/%TOPIC%/$topic/gos; } @@ -1123,13 +1124,13 @@ $info->{user} = $u; } if( $theAttr eq "username" ) { - return $info->{user}; + return $info->{user}->login(); } if( $theAttr eq "wikiname" ) { - return $this->users()->userToWikiName( $info->{user}, 1 ); + return $info->{user}->wikiName(); } if( $theAttr eq "wikiusername" ) { - return $this->users()->userToWikiName( $info->{user} ); + return $info->{user}->webDotWikiName(); } if( $theAttr eq "date" ) { return &TWiki::formatTime( $info->{date} ); @@ -1212,22 +1213,6 @@ =pod ----++ sub wikiName ( $theWikiUserName ) - -Not yet documented. - -=cut - -sub wikiName -{ - my( $theWikiUserName ) = @_; - - $theWikiUserName =~ s/^.*\.//o; - return $theWikiUserName; -} - -=pod - ---++ sub breakName ( $theText, $theParams ) Not yet documented. Modified: twiki/branches/DEVELOP/lib/TWiki/Store/RcsFile.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Store/RcsFile.pm 2005-01-20 16:38:24 UTC (rev 3554) +++ twiki/branches/DEVELOP/lib/TWiki/Store/RcsFile.pm 2005-01-20 19:42:37 UTC (rev 3555) @@ -119,7 +119,7 @@ { my( $self ) = @_; my $fileDate = $self->getTimestamp(); - return ( "", 1, $fileDate, $TWiki::defaultUserName, "Default revision information - no revision file" ); + return ( "", 1, $fileDate, $TWiki::defaultUser, "Default revision information - no revision file" ); } # ====================== @@ -428,22 +428,23 @@ # ====================== =pod ----++ sub setLock ( $self, $lock, $userName ) +---++ sub setLock ( $self, $lock, $user ) -Set a twiki lock on the topic +Set a twiki lock on the topic, if $lock, otherwise clear it. +$user is a wikiname. =cut to implementation sub setLock { - my( $self, $lock, $userName ) = @_; + my( $self, $lock, $user ) = @_; - $userName = $self->{session}->{userName} if( ! $userName ); + $user = $self->{session}->{user} unless $user; my $lockFilename = $self->_makeFileName( ".lock" ); if( $lock ) { my $lockTime = time(); - $self->_saveFile( $lockFilename, "$userName\n$lockTime" ); + $self->_saveFile( $lockFilename, "$user\n$lockTime" ); } else { unlink "$lockFilename"; } Modified: twiki/branches/DEVELOP/lib/TWiki/Store/RcsWrap.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Store/RcsWrap.pm 2005-01-20 16:38:24 UTC (rev 3554) +++ twiki/branches/DEVELOP/lib/TWiki/Store/RcsWrap.pm 2005-01-20 19:42:37 UTC (rev 3555) @@ -101,18 +101,18 @@ # ====================== =pod ----++ sub addRevision ( $self, $text, $comment, $userName ) +---++ sub addRevision ( $self, $text, $comment, $user ) -Add new revision. Replace file (if exists) with text +Add new revision. Replace file (if exists) with text. +$user is a wikiname. =cut sub addRevision { - my( $self, $text, $comment, $userName ) = @_; - + my( $self, $text, $comment, $user ) = @_; $self->_save( $self->{file}, \$text ); - return $self->_ci( $self->{file}, $comment, $userName ); + return $self->_ci( $self->{file}, $comment, $user ); } # ====================== @@ -120,9 +120,10 @@ ---++ sub replaceRevision ( $self, $text, $comment, $user, $date ) -Replace the top revision -Return non empty string with error message if there is a problem -| $date | is on epoch seconds | +Replace the top revision. +Return non empty string with error message if there is a problem. +$date is in epoch seconds. +$user is a wikiname. =cut @@ -292,6 +293,7 @@ If revision file is missing, information based on actual file is returned. Date return in epoch seconds. Revision returned as a number. +User returned as a wikiname. =cut @@ -438,7 +440,7 @@ # ====================== sub _ci { - my( $self, $file, $comment, $userName ) = @_; + my( $self, $file, $comment, $user ) = @_; # Check that we can write the file being checked in. This won't check # that $file,v is writable, but it _will_ trap 99% of all common @@ -449,7 +451,7 @@ my ($rcsOutput, $exit) = $self->{session}->{sandbox}->readFromProcess ( $self->{ciCmd}, - USERNAME => $userName, + USERNAME => $user, FILENAME => $file, COMMENT => $comment ); if( $exit && $rcsOutput =~ /no lock set by/ ) { @@ -461,7 +463,7 @@ # re-do the ci command ( $rcsOutput, $exit ) = $self->{session}->{sandbox}->readFromProcess( $self->{ciCmd}, - USERNAME => $userName, + USERNAME => $user, FILENAME => $file, COMMENT => $comment ); } Modified: twiki/branches/DEVELOP/lib/TWiki/Store.pm =================================================================== --- twiki/branches/DEVELOP/lib/TWiki/Store.pm 2005-01-20 16:38:24 UTC (rev 3554) +++ twiki/branches/DEVELOP/lib/TWiki/Store.pm 2005-01-20 19:42:37 UTC (rev 3555) @@ -37,7 +37,9 @@ use File::Copy; use Time::Local; use TWiki::Meta; +use TWiki::AccessControlException; use Assert; +use Error qw( :try ); use strict; @@ -70,7 +72,6 @@ if( $@ ) { die "$this->{IMPL} compile failed $@"; } - $this->{ACCESSFAILED} = ""; $this->{STORESETTINGS} = $storeSettings; return $this; @@ -99,16 +100,16 @@ =pod ----++ readTopic($user, $web, $topic, $version, $internal) -> ($meta, $text) +---++ readTopic($user, $web, $topic, $version) -> ($meta, $text) Reads the given version of a topic and it's meta-data. If the version is undef, then read the most recent version. The version number must be an integer, or undef for the latest version. -If $internal is false, view permission will be required for the topic -read to be successful. A failed topic read is indicated by setting -the status returned by accessFailed(). Permissions are checked for -TWiki::wikiUserName, there is no way to override this. +If $user is defined, view permission will be required for the topic +read to be successful. Access control violations are flagged by a +TWiki::AccessControlException. Permissions are checked for the user +name passed in. If the topic contains a web specification (is of the form Web.Topic) the web specification will override whatever is passed in $theWeb. @@ -119,28 +120,27 @@ =cut sub readTopic { - my( $this, $user, $theWeb, $theTopic, $version, $internal ) = @_; + my( $this, $user, $theWeb, $theTopic, $version ) = @_; ASSERT(ref($this) eq "TWiki::Store") if DEBUG; - ASSERT(defined($internal)) if DEBUG; - my $text = $this->readTopicRaw( $user, $theWeb, $theTopic, $version, $internal ); + my $text = $this->readTopicRaw( $user, $theWeb, $theTopic, $version ); my $meta = $this->extractMetaData( $theWeb, $theTopic, \$text ); return( $meta, $text ); } =pod ----++ readTopicRaw( $user, $web, $topic, $version, $internal ) +---++ readTopicRaw( $user, $web, $topic, $version ) Return value: $topicText Reads the given version of a topic, without separating out any embedded meta-data. If the version is undef, then read the most recent version. The version number must be an integer or undef. -If $internal is false, view access permission will be checked. If permission -is not granted, then an error message will be returned in $text, and set -as the return value of accessFailed. Permissions are checked for -TWiki::wikiUserName, there is no way to overrides this. +If $user is defined, view permission will be required for the topic +read to be successful. Access control violations are flagged by a +TWiki::AccessControlException. Permissions are checked for the user +name passed in. If the topic contains a web specification (is of the form Web.Topic) the web specification will override whatever is passed in $theWeb. @@ -153,9 +153,8 @@ =cut sub readTopicRaw { - my( $this, $user, $theWeb, $theTopic, $version, $internal ) = @_; + my( $this, $user, $theWeb, $theTopic, $version ) = @_; ASSERT(ref($this) eq "TWiki::Store") if DEBUG; - ASSERT(defined($internal)) if DEBUG; # test if theTopic contains a webName to override $theWeb ( $theWeb, $theTopic ) = @@ -170,39 +169,18 @@ $text = $topicHandler->getRevision( $version ); } - my $viewAccessOK = 1; - unless( $internal ) { - $viewAccessOK = - $this->security()->checkAccessPermission( "view", $user, - $text, $theTopic, $theWeb ); + if( $user && + !$this->security()->checkAccessPermission + ( "view", $user, $text, $theTopic, $theWeb )) { + throw TWiki::AccessControlException( "VIEW", $user, + $theWeb, $theTopic ); } - unless( $viewAccessOK ) { - # SMELL: TWiki::Func::readTopicText will break if the following - # text changes - $text = "No permission to read topic $theWeb.$theTopic - perhaps you need to log in?\n"; - $this->{ACCESSFAILED} .= " $theWeb.$theTopic"; - } - return $text; } =pod ----++ sub accessFailed () -Returns a string containing the names of all topics that have have had access -failures since this Store was created. - -=cut -sub accessFailed { - my $this = shift; - ASSERT(ref($this) eq "TWiki::Store") if DEBUG; - - return $this->{ACCESSFAILED}; -} - -=pod - ---++ sub moveAttachment ( $oldWeb, $oldTopic, $newWeb, $newTopic, $theAttachment, $user ) Move an attachment from one topic to another. @@ -219,13 +197,29 @@ my( $this, $oldWeb, $oldTopic, $newWeb, $newTopic, $theAttachment, $user ) = @_; ASSERT(ref($this) eq "TWiki::Store") if DEBUG; - ASSERT(defined($user)) if DEBUG; + ASSERT(ref($user) eq "TWiki::User") if DEBUG; $this->lockTopic( $user, $oldWeb, $oldTopic ); - my $wName = $this->users()->userToWikiName( $user ); + my( $ometa, $otext ) = $this->readTopic( undef, $oldWeb, $oldTopic ); + if( $user && + !$this->security()->checkAccessPermission + ( "change", $user, $otext, $oldTopic, $oldWeb )) { + throw TWiki::AccessControlException( "CHANGE", $user, + $oldWeb, $oldTopic ); + } + + my ( $nmeta, $ntext ) = $this->readTopic( undef, $newWeb, $newTopic ); + if( $user && + !$this->security()->checkAccessPermission + ( "change", $user, $ntext, $newTopic, $newWeb )) { + throw TWiki::AccessControlException( "CHANGE", $user, + $newWeb, $newTopic ); + } + # Remove file attachment from old topic - my $topicHandler = $this->_getTopicHandler( $oldWeb, $oldTopic, $theAttachment ); + my $topicHandler = + $this->_getTopicHandler( $oldWeb, $oldTopic, $theAttachment ); my $error = $topicHandler->moveMe( $newWeb, $newTopic ); if( $error ) { @@ -234,12 +228,11 @@ return $error; } - my( $meta, $text ) = $this->readTopic( $wName, $oldWeb, $oldTopic, 1 ); my %fileAttachment = - $meta->findOne( "FILEATTACHMENT", $theAttachment ); - $meta->remove( "FILEATTACHMENT", $theAttachment ); + $ometa->findOne( "FILEATTACHMENT", $theAttachment ); + $ometa->remove( "FILEATTACHMENT", $theAttachment ); $error = $this->_noHandlersSave( $user, $oldWeb, $oldTopic, - $text, $meta, + $otext, $ometa, { notify => 0 } ); $this->unlockTopic( $user, $oldWeb, $oldTopic ); @@ -249,15 +242,14 @@ } # Add file attachment to new topic - ( $meta, $text ) = $this->readTopic( $wName, $newWeb, $newTopic, 1 ); $fileAttachment{"movefrom"} = "$oldWeb.$oldTopic"; $fileAttachment{"moveby"} = $user; $fileAttachment{"movedto"} = "$newWeb.$newTopic"; $fileAttachment{"movedwhen"} = time(); - $meta->put( "FILEATTACHMENT", %fileAttachment ); + $nmeta->put( "FILEATTACHMENT", %fileAttachment ); - $error = $this->_noHandlersSave( $user, $newWeb, $newTopic, $text, - $meta, { notify => 0, + $error = $this->_noHandlersSave( $user, $newWeb, $newTopic, $ntext, + $nmeta, { notify => 0, comment => "moved" } ); $this->unlockTopic( $user, $newWeb, $newTopic ); @@ -273,21 +265,33 @@ =pod ----++ sub getAttachmentStream( $web, $topic, $attName ) -> stream +---++ sub getAttachmentStream( $user, $web, $topic, $attName ) -> stream +| =$user= | the user doing the reading, or undef if no access checks | | =$web= | The web | | =$topic= | The topic | | =$attName= | Name of the attachment | + Open a standard input stream from an attachment. Will return undef if the stream could not be opened (permissions, or nonexistant etc) +If $user is defined, view permission will be required for the topic +read to be successful. Access control violations are flagged by a +TWiki::AccessControlException. Permissions are checked for the user +name passed in. + =cut sub getAttachmentStream { - my $this = shift; - #my ( $web, $topic, $att ) = @_; + my ( $this, $user, $web, $topic, $att ) = @_; ASSERT(ref($this) eq "TWiki::Store") if DEBUG; - my $topicHandler = $this->_getTopicHandler( @_ ); + if( $user && + !$this->security()->checkAccessPermission + ( "view", $user, undef, $topic, $web )) { + throw TWiki::AccessControlException( "VIEW", $user, $web, $topic ); + } + + my $topicHandler = $this->_getTopicHandler( $web, $topic, $att ); my $strm; my $fp = $topicHandler->{file}; if ( $fp ) { @@ -381,7 +385,6 @@ return $out; } - =pod ---++ sub renameTopic( $oldWeb, $oldTopic, $newWeb, $newTopic, $doChangeRefTo $user ) -> error string or undef @@ -405,9 +408,24 @@ # will block $this->lockTopic( $user, $oldWeb, $oldTopic ); + my $otext = $this->readTopicRaw( undef, $oldWeb, $oldTopic ); + if( $user && + !$this->security()->checkAccessPermission + ( "change", $user, $otext, $oldTopic, $oldWeb )) { + throw TWiki::AccessControlException( "CHANGE", $user, + $oldWeb, $oldTopic ); + } + + my ( $nmeta, $ntext ) = $this->readTopic( undef, $newWeb, $newTopic ); + if( $user && + !$this->security()->checkAccessPermission + ( "change", $user, $ntext, $newTopic, $newWeb )) { + throw TWiki::AccessControlException( "CHANGE", $user, + $newWeb, $newTopic ); + } + my $topicHandler = $this->_getTopicHandler( $oldWeb, $oldTopic, "" ); my $error = $topicHandler->moveMe( $newWeb, $newTopic ); - my $wName = $this->users()->userToWikiName( $user ); if( ! $error ) { my $time = time(); @@ -416,7 +434,7 @@ "to" => "$newWeb.$newTopic", "date" => "$time", "by" => "$user" ); - my $text = $this->readTopicRaw( $wName, $newWeb, $newTopic, undef, 1 ); + my $text = $this->readTopicRaw( undef, $newWeb, $newTopic, undef ); if( ( $oldWeb ne $newWeb ) && $doChangeRefTo ) { $text = $this->_changeRefTo( $text, $oldWeb, $oldTopic ); } @@ -439,7 +457,7 @@ =pod ----++ sub updateReferringPages ( $oldWeb, $oldTopic, $wikiUserName, $newWeb, $newTopic, @refs ) -> ( count of lock failures, result text) +---++ sub updateReferringPages( $oldWeb, $oldTopic, $user, $newWeb, $newTopic, @refs ) -> ( count of lock failures, result text) Update pages that refer to a page that is being renamed/moved. Return the number of updates that failed due to active locks and a message. @@ -454,12 +472,12 @@ sub updateReferringPages { my ( $this, $oldWeb, $oldTopic, $user, $newWeb, $newTopic, @refs ) = @_; ASSERT(ref($this) eq "TWiki::Store") if DEBUG; + ASSERT(ref($user) eq "TWiki::User") if DEBUG; my $result = ""; my $preTopic = '^|\W'; # Start of line or non-alphanumeric my $postTopic = '$|\W'; # End of line or non-alphanumeric my $spacedTopic = TWiki::searchableTopic( $oldTopic ); - my $wikiUserName = $this->users()->userToWikiName( $user ); my $lockFailures = 0; while ( @refs ) { @@ -472,13 +490,12 @@ if ( $this->topicExists($itemWeb, $itemTopic) ) { $this->lockTopic( $user, $itemWeb, $itemTopic ); my $scantext = - $this->readTopicRaw( $wikiUserName, $itemWeb, $itemTopic, - undef, 0 ); - if( ! $this->security()->checkAccessPermission( "change", - $wikiUserName, - $scantext, - $itemWeb, - $itemTopic ) ) { + $this->readTopicRaw( undef, $itemWeb, $itemTopic, undef ); + if( $user && !$this->security()->checkAccessPermission( "change", + $user, + $scantext, + $itemWeb, + $itemTopic ) ) { # This shouldn't happen, as search will not return, but # check to be on the safe side $this->{session}->writeWarning( "rename: attempt to change $itemWeb.$itemTopic without permission" ); @@ -536,18 +553,30 @@ =pod ----++ sub readAttachmentVersion ( $theWeb, $theTopic, $theAttachment, $theRev ) +---++ sub readAttachment( $user, $theWeb, $theTopic, $theAttachment, $theRev ) Read the given version of an attachment, returning the content. +View permission on the topic is required for the +read to be successful. Access control violations are flagged by a +TWiki::AccessControlException. Permissions are checked for the user +name passed in. + =cut -sub readAttachmentVersion { - my ( $this, $theWeb, $theTopic, $theAttachment, $theRev ) = @_; +sub readAttachment { + my ( $this, $user, $theWeb, $theTopic, $theAttachment, $theRev ) = @_; + ASSERT(ref($this) eq "TWiki::Store") if DEBUG; - my $topicHandler = $this->_getTopicHandler( $theWeb, $theTopic, $theAttachment ); - return $topicHandler->getRevision( $theRev ); + if( $user && + !$this->security()->checkAccessPermission + ( "change", $user, undef, $theTopic, $theWeb )) { + throw TWiki::AccessControlException( "CHANGE", $user, $theWeb, $theTopic ); + } + + my $topicHandler = $this->_getTopicHandler( $theWeb, $theTopic, $theAttachment ); + return $topicHandler->getRevision( $theRev ); } =pod @@ -627,6 +656,8 @@ my( $rcsOut, $rev, $date, $user, $comment ) = $topicHandler->getRevisionInfo( $theRev ); + $user = $this->users()->findUser( $user ) if $user; + return ( $date, $user, $rev, $comment ); } @@ -677,10 +708,18 @@ sub saveTopic { my( $this, $user, $web, $topic, $text, $meta, $options ) = @_; ASSERT(ref($this) eq "TWiki::Store") if DEBUG; + ASSERT(ref($user) eq "TWiki::User") if DEBUG; ASSERT(ref($meta) eq "TWiki::Meta") if DEBUG; $options = {} unless defined( $options ); + if( $user && + !$this->security()->checkAccessPermission + ( "change", $user, undef, $topic, $web )) { + + throw TWiki::AccessControlException( "CHANGE", $user, $web, $topic ); + } + # SMELL: Staggeringly inefficient code that adds meta-data for # Plugin callback. Why not simply pass the meta in? It would be far # more sensible. @@ -688,10 +727,10 @@ $this->{session}->{plugins}->beforeSaveHandler( $text, $topic, $web ); # remove meta data again! $meta = $this->extractMetaData( $web, $topic, \$text ); + my $error = $this->_noHandlersSave( $user, $web, $topic, $text, $meta, $options ); - $text = _writeMeta( $meta, $text ); # add meta data for Plugin callback $this->{session}->{plugins}->afterSaveHandler( $text, $topic, $web, $error ); return $error; } @@ -721,14 +760,22 @@ sub saveAttachment { my( $this, $web, $topic, $attachment, $user, $opts ) = @_; ASSERT(ref($this) eq "TWiki::Store") if DEBUG; + ASSERT(ref($user) eq "TWiki::User") if DEBUG; ASSERT(defined($opts)) if DEBUG; my $action; $this->lockTopic( $user, $web, $topic ); # update topic - my( $meta, $text ) = $this->readTopic( $user, $web, $topic, undef, 1 ); + my( $meta, $text ) = $this->readTopic( undef, $web, $topic, undef ); + if( $user && + !$this->security()->checkAccessPermission + ( "change", $user, $text, $topic, $web )) { + + throw TWiki::AccessControlException( "CHANGE", $user, $web, $topic ); + } + if ( $opts->{file} ) { my $fileVersion = $this->getRevisionNumber( $web, $topic, $attachment ); @@ -747,7 +794,7 @@ $topic, $web ); my $error = $topicHandler->addRevision( $opts->{file}, $opts->{comment}, - $user ); + $user->wikiName() ); $this->{session}->{plugins}->afterAttachmentSaveHandler( \%attrs, $topic, $web, $error ); @@ -770,7 +817,7 @@ } if( $opts->{createlink} ) { - $text .= $this->attach()->getAttachmentLink( $web, $topic, + $text .= $this->attach()->getAttachmentLink( $user, $web, $topic, $attachment, $meta ); } @@ -790,8 +837,10 @@ # Return non-null string if there is an error. # FIXME: does rev info from meta work if user saves a topic with no change? sub _noHandlersSave { - my( $this, $userName, $web, $topic, $text, $meta, $options ) = @_; + my( $this, $user, $web, $topic, $text, $meta, $options ) = @_; + ASSERT(ref($user) eq "TWiki::User") if DEBUG; + my $topicHandler = $this->_getTopicHandler( $web, $topic ); my $currentRev = $topicHandler->numRevisions() || 0; @@ -803,11 +852,11 @@ my $mtime2 = time(); if( abs( $mtime2 - $mtime1 ) < $TWiki::editLockTime ) { - my( $date, $user ) = + my( $date, $revuser ) = $this->getRevisionInfo( $web, $topic, $currentRev, undef, $topicHandler ); # same user? - if( $user eq $userName ) { + if( $revuser->equals( $user )) { return repRev( @_ ); } } @@ -820,27 +869,24 @@ $text =~ s/([^\n\r])$/$1\n/os; # will block - $this->lockTopic( $userName, $web, $topic ); - + $this->lockTopic( $user, $web, $topic ); my $error = - $topicHandler->addRevision( $text, $options->{comment}, $userName ); + $topicHandler->addRevision( $text, $options->{comment}, + $user->wikiName() ); - $this->unlockTopic( $userName, $web, $topic ); + $this->unlockTopic( $user, $web, $topic ); return $error if( $err... [truncated message content] |