Skip to content

Commit

Permalink
Merge pull request #70 from mlibrary/projection
Browse files Browse the repository at this point in the history
Projection scenarios
  • Loading branch information
botimer authored Feb 28, 2024
2 parents d7e335f + 90742cb commit 25ce33f
Show file tree
Hide file tree
Showing 29 changed files with 408 additions and 156 deletions.
21 changes: 21 additions & 0 deletions apache/conf/test-site.conf
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@

# LogLevel debug

RewriteEngine on
RewriteRule "^/projection/private/but-not-really/" "/projection/public/index.html" [PT]
RewriteRule "^/projection/public/but-not-really/" "/projection/private/index.html" [PT]
RewriteRule "^/projection/private-also/but-not-really/" "/projection/private/index.html" [PT]

<Location /hosted>
ScriptAlias /lauth/test-site/cgi/printenv
AuthType RemoteUser
Expand All @@ -26,6 +31,22 @@
Require all granted
</Directory>

<Location "/projection/private/">
AuthType RemoteUser
<RequireAll>
Require valid-user
Require lauth
</RequireAll>
</Location>

<Location "/projection/private-also/">
AuthType RemoteUser
<RequireAll>
Require valid-user
Require lauth
</RequireAll>
</Location>

<Location "/restricted-by-username/">
AuthType Basic
AuthName "Restricted Resource"
Expand Down
102 changes: 102 additions & 0 deletions db/projection.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
INSERT INTO aa_coll VALUES(
'projection-public', -- uniqueIdentifier
'projection-public', -- commonName
'auth system testing: projection',
'unused', -- dlpsClass
'none', -- dlpsSource (unused)
'pw', -- dlpsAuthenMethod
'n', -- dlpsAuthzType
't', -- dlpsPartlyPublic
0, -- manager
CURRENT_TIMESTAMP, 'root', -- modified info
'f' -- deleted
);

INSERT INTO aa_coll_obj VALUES(
'www.lauth.local', -- server hostname, not vhost
'/lauth/test-site/web/projection/public%', -- dlpsPath
'projection-public', -- coll.uniqueIdentifier
CURRENT_TIMESTAMP, 'root', -- modified info
'f' -- deleted
);

INSERT INTO aa_coll VALUES(
'projection-private', -- uniqueIdentifier
'projection-private', -- commonName
'auth system testing: projection',
'unused', -- dlpsClass
'none', -- dlpsSource (unused)
'pw', -- dlpsAuthenMethod
'n', -- dlpsAuthzType
'f', -- dlpsPartlyPublic
0, -- manager
CURRENT_TIMESTAMP, 'root', -- modified info
'f' -- deleted
);

INSERT INTO aa_coll_obj VALUES(
'www.lauth.local', -- server hostname, not vhost
'/lauth/test-site/web/projection/private%', -- dlpsPath
'projection-private', -- coll.uniqueIdentifier
CURRENT_TIMESTAMP, 'root', -- modified info
'f' -- deleted
);

INSERT INTO aa_may_access VALUES(
NULL, -- uniqueIdentifier
'lauth-allowed', -- userid
NULL, -- user_grp
NULL, -- inst
'projection-private', -- coll
CURRENT_TIMESTAMP,
'root',
NULL,
'f'
);

INSERT INTO aa_coll VALUES(
'projection-private-also', -- uniqueIdentifier
'projection-private-also', -- commonName
'auth system testing: projection',
'unused', -- dlpsClass
'none', -- dlpsSource (unused)
'pw', -- dlpsAuthenMethod
'n', -- dlpsAuthzType
'f', -- dlpsPartlyPublic
0, -- manager
CURRENT_TIMESTAMP, 'root', -- modified info
'f' -- deleted
);

INSERT INTO aa_coll_obj VALUES(
'www.lauth.local', -- server hostname, not vhost
'/lauth/test-site/web/projection/private-also%', -- dlpsPath
'projection-private-also', -- coll.uniqueIdentifier
CURRENT_TIMESTAMP, 'root', -- modified info
'f' -- deleted
);

INSERT INTO aa_user VALUES(
'lauth-allowed-also',NULL,'Lauth',NULL,'Tester-Allowed','[email protected]',
NULL, -- org unit
'Library auth system test user - this user is granted access',
'Ann Arbor','MI','48109-119',NULL,NULL,'Staff',NULL,
'!none', -- umich id, !none
'@umich.edu', -- password, @umich.edu MAY signify SSO
0,NULL,
CURRENT_TIMESTAMP,'root', -- modified
NULL, -- expiry
'f'
);

INSERT INTO aa_may_access VALUES(
NULL, -- uniqueIdentifier
'lauth-allowed-also', -- userid
NULL, -- user_grp
NULL, -- inst
'projection-private-also', -- coll
CURRENT_TIMESTAMP,
'root',
NULL,
'f'
)
1 change: 1 addition & 0 deletions db/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,5 @@ if [[ $all == "true" ]]; then
mariadb --user=$user --host=$host --port=$port --password=$password $database < "$directory/test-fixture.sql"
mariadb --user=$user --host=$host --port=$port --password=$password $database < "$directory/network.sql"
mariadb --user=$user --host=$host --port=$port --password=$password $database < "$directory/delegation.sql"
mariadb --user=$user --host=$host --port=$port --password=$password $database < "$directory/projection.sql"
fi
6 changes: 3 additions & 3 deletions lauth/app/ops/authorize.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def call
collection = collection_repo.find_by_uri(request.uri)
case collection.dlpsAuthzType
when "n"
normal_mode
normal_mode(collection: collection)
when "d"
delegated_mode(collection: collection)
else
Expand Down Expand Up @@ -52,10 +52,10 @@ def delegated_mode(collection:)
)
end

def normal_mode
def normal_mode(collection:)
relevant_grants = grant_repo.for(
username: request.user,
uri: request.uri,
collection: collection,
client_ip: request.client_ip
)
determination = if relevant_grants.any?
Expand Down
18 changes: 18 additions & 0 deletions lauth/app/repositories/collection_repo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,30 @@ class CollectionRepo < ROM::Repository[:collections]
include Deps[container: "persistence.rom"]
struct_namespace Lauth

# Find a collection via its uri location, specifically the dlpsPath.
# This prefers the "most specific" location. We define that here as
# the path with the deepest nesting, and in case of a tie we then prefer
# whichever path is longest. I.e. the path /foo/bar/baz% is more specific
# than /foo/bar/b%.
# There is an assumption that all dlpsPath values end in the SQL wildcard %.
# @param uri [String]
# @return [Collection]
def find_by_uri(uri)
dataset = collections
.dataset
.where(collections[:dlpsDeleted].is("f"))
.join(locations.name.dataset, coll: :uniqueIdentifier, dlpsDeleted: "f")
.where(Sequel.ilike(uri, locations[:dlpsPath]))
.select_append(Sequel.as( # count the slashes
Sequel.expr {
char_length(:dlpsPath) - char_length(replace(:dlpsPath, "/", ""))
},
:path_depth
))
.order(
Sequel.desc(:path_depth),
Sequel.desc(Sequel.expr { length(:dlpsPath) })
)
collections.class.new(dataset).to_a.first
end

Expand Down
82 changes: 27 additions & 55 deletions lauth/app/repositories/grant_repo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,62 +10,50 @@ def find(id)

def for_collection_class(username:, client_ip:, collection_class:)
smallest_network = smallest_network_for_ip(client_ip)

ds = grants
.dataset
.where(grants[:dlpsDeleted].is("f"))
.join(collections.name.dataset, uniqueIdentifier: :coll, dlpsDeleted: "f")
.left_join(users.name.dataset, userid: grants[:userid], dlpsDeleted: "f")
.left_join(institutions.name.dataset, uniqueIdentifier: grants[:inst], dlpsDeleted: "f")
.left_join(institution_memberships.name.dataset, inst: grants[:inst], dlpsDeleted: "f")
.left_join(groups.name.dataset, uniqueIdentifier: grants[:user_grp], dlpsDeleted: "f")
.left_join(group_memberships.name.dataset, user_grp: grants[:user_grp], dlpsDeleted: "f")
.left_join(Sequel.as(smallest_network, :smallest), inst: grants[:inst])
ds = base_grants_for(username: username, network: smallest_network)
.join(collections.name.dataset, uniqueIdentifier: grants[:coll], dlpsDeleted: "f")
.where(collections[:dlpsClass] => collection_class)
.where(
Sequel.|(
Sequel.&(
Sequel.~(users[:userid] => nil),
{users[:userid] => username}
),
Sequel.&(
Sequel.~(institutions[:uniqueIdentifier] => nil),
Sequel.~(institution_memberships[:userid] => nil),
{institution_memberships[:userid] => username}
),
Sequel.&(
Sequel.~(groups[:uniqueIdentifier] => nil),
Sequel.~(group_memberships[:userid] => nil),
{group_memberships[:userid] => username}
),
Sequel.&(
Sequel.~(Sequel[:smallest][:inst] => nil),
{Sequel[:smallest][:dlpsAccessSwitch] => "allow"}
)
)
)

rel = grants.class.new(ds)
rel.to_a
end

def for(username:, uri:, client_ip: nil)
def for(username:, collection:, client_ip: nil)
return [] unless collection&.dlpsDeleted == "f"

smallest_network = smallest_network_for_ip(client_ip)
ds = base_grants_for(username: username, network: smallest_network)
.where(grants[:coll] => collection.uniqueIdentifier)

rel = grants.class.new(ds)
rel.combine(:user, institutions: {institution_memberships: :users}).to_a
end

private

ds = grants
def smallest_network_for_ip(client_ip)
ip = client_ip ? IPAddr.new(client_ip).to_i : nil
networks
.dataset
.where(dlpsDeleted: "f")
.where { dlpsAddressStart <= ip }
.where { dlpsAddressEnd >= ip }
.select_append(Sequel.as(Sequel.expr { dlpsAddressEnd - dlpsAddressStart }, :block_size))
.order(Sequel.asc(:block_size)).limit(1)
end

def base_grants_for(username:, network:)
grants
.dataset
.where(grants[:dlpsDeleted].is("f"))
.join(collections.name.dataset, uniqueIdentifier: :coll, dlpsDeleted: "f")
.join(locations.name.dataset, coll: :uniqueIdentifier, dlpsDeleted: "f")
.left_join(users.name.dataset, userid: grants[:userid], dlpsDeleted: "f")
.left_join(institutions.name.dataset, uniqueIdentifier: grants[:inst], dlpsDeleted: "f")
.left_join(institution_memberships.name.dataset, inst: :uniqueIdentifier, dlpsDeleted: "f")
.left_join(Sequel.as(users.name.dataset, :inst_users), userid: :userid, dlpsDeleted: "f")
.left_join(groups.name.dataset, uniqueIdentifier: grants[:user_grp], dlpsDeleted: "f")
.left_join(group_memberships.name.dataset, user_grp: :uniqueIdentifier, dlpsDeleted: "f")
.left_join(Sequel.as(users.name.dataset, :group_users), userid: :userid, dlpsDeleted: "f")
.left_join(Sequel.as(smallest_network, :smallest), inst: institutions[:uniqueIdentifier])
.where(Sequel.ilike(uri, locations[:dlpsPath]))
.left_join(Sequel.as(network, :smallest), inst: institutions[:uniqueIdentifier])
.where(
Sequel.|(
Sequel.&(
Expand All @@ -88,22 +76,6 @@ def for(username:, uri:, client_ip: nil)
)
)
)

rel = grants.class.new(ds)
rel.combine(:user, collections: :locations, institutions: {institution_memberships: :users}).to_a
end

private

def smallest_network_for_ip(client_ip)
ip = client_ip ? IPAddr.new(client_ip).to_i : nil
networks
.dataset
.where(dlpsDeleted: "f")
.where { dlpsAddressStart <= ip }
.where { dlpsAddressEnd >= ip }
.select_append(Sequel.as(Sequel.expr { dlpsAddressEnd - dlpsAddressStart }, :block_size))
.order(Sequel.asc(:block_size)).limit(1)
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions lauth/spec/ops/authorize_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
it "allows a request with a grant" do
allow(grant_repo).to receive(:for).with(
username: "cool_dude",
uri: "/some/uri/",
collection: anything,
client_ip: "10.11.22.33"
).and_return([:somegrant])

Expand All @@ -36,7 +36,7 @@
it "denies a request without any grants" do
allow(grant_repo).to receive(:for).with(
username: "cool_dude",
uri: "/some/uri/",
collection: anything,
client_ip: "10.11.22.33"
).and_return([])

Expand Down
11 changes: 7 additions & 4 deletions lauth/spec/repositories/collection_repo_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
subject(:repo) { Lauth::Repositories::CollectionRepo.new }

describe "#find_by_uri" do
it "finds the collection for the given location path" do
collection = Lauth::Fab::Collection.create
Factory[:location, dlpsPath: "/cool/path%", collection: collection]
it "finds the most specific collection for the given location path" do
expected_collection = Lauth::Fab::Collection.create(uniqueIdentifier: "expected-collection")
wrong_collection = Lauth::Fab::Collection.create
Factory[:location, dlpsPath: "/cool/p%", collection: wrong_collection]
Factory[:location, dlpsPath: "/uncool%", collection: wrong_collection]
Factory[:location, dlpsPath: "/cool/path%", collection: expected_collection]

found = repo.find_by_uri("/cool/path")

expect(found.uniqueIdentifier).to eq collection.uniqueIdentifier
expect(found.uniqueIdentifier).to eq "expected-collection"
end
end

Expand Down
Loading

0 comments on commit 25ce33f

Please sign in to comment.