From 06d67ed4af9d1493a98c2751591ce632c628dcc7 Mon Sep 17 00:00:00 2001 From: Adrian Damian <Adrian.Damian@nrc.ca> Date: Fri, 27 Jun 2014 11:47:26 -0700 Subject: [PATCH] Added the core authorization classes - code review changes --- projects/cadcUtil/doc/uml/UserAuth.png | Bin 16427 -> 17155 bytes .../src/ca/nrc/cadc/auth/model/Group.java | 9 +- .../ca/nrc/cadc/auth/model/GroupProperty.java | 24 +-- .../ca/nrc/cadc/auth/model/PosixDetails.java | 2 +- .../src/ca/nrc/cadc/auth/model/User.java | 6 +- .../ca/nrc/cadc/auth/model/UserDetails.java | 158 +----------------- .../src/ca/nrc/cadc/auth/model/GroupTest.java | 36 +++- .../src/ca/nrc/cadc/auth/model/UserTest.java | 27 +-- 8 files changed, 67 insertions(+), 195 deletions(-) diff --git a/projects/cadcUtil/doc/uml/UserAuth.png b/projects/cadcUtil/doc/uml/UserAuth.png index c36dfcc1fe9c2513edec0e715a4318b130ea89a2..64354ac504dff79d1f26a7e0e17100cb82bac64a 100644 GIT binary patch literal 17155 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 E0o1xNmH+?% literal 16427 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 BrJeu) diff --git a/projects/cadcUtil/src/ca/nrc/cadc/auth/model/Group.java b/projects/cadcUtil/src/ca/nrc/cadc/auth/model/Group.java index 30c155ce..a5dc8872 100644 --- a/projects/cadcUtil/src/ca/nrc/cadc/auth/model/Group.java +++ b/projects/cadcUtil/src/ca/nrc/cadc/auth/model/Group.java @@ -76,7 +76,8 @@ public class Group * Ctor. * * @param groupID - * Unique ID for the group + * Unique ID for the group. Must be a valid URI fragment component, + * so it's restricted to alphanumeric and "-", ".","_","~" characters. * @param owner * Owner/Creator of the group. */ @@ -87,6 +88,12 @@ public class Group { throw new IllegalArgumentException("Null groupID"); } + + // check for invalid path characters in groupID + if(!groupID.matches("^[a-zA-Z0-9\\-\\.~_]*$")) + throw new IllegalArgumentException("Invalid group ID " + groupID + + ": may not contain space ( ), slash (/), escape (\\), or percent (%)"); + this.groupID = groupID; if(owner == null) { diff --git a/projects/cadcUtil/src/ca/nrc/cadc/auth/model/GroupProperty.java b/projects/cadcUtil/src/ca/nrc/cadc/auth/model/GroupProperty.java index 743af8e0..cee88725 100644 --- a/projects/cadcUtil/src/ca/nrc/cadc/auth/model/GroupProperty.java +++ b/projects/cadcUtil/src/ca/nrc/cadc/auth/model/GroupProperty.java @@ -140,9 +140,6 @@ public class GroupProperty final int prime = 31; int result = 1; result = prime * result + ((key == null) ? 0 : key.hashCode()); - result = prime * result + (readOnly ? 1231 : 1237); - result = prime * result - + ((value == null) ? 0 : value.hashCode()); return result; } @@ -165,26 +162,7 @@ public class GroupProperty return false; } GroupProperty other = (GroupProperty) obj; - if (key == null) - { - if (other.key != null) - { - return false; - } - } - else if (!key.equals(other.key)) - { - return false; - } - if (readOnly != other.readOnly) - { - return false; - } - if (!value.equals(other.value)) - { - return false; - } - return true; + return key.equals(other.key); } @Override diff --git a/projects/cadcUtil/src/ca/nrc/cadc/auth/model/PosixDetails.java b/projects/cadcUtil/src/ca/nrc/cadc/auth/model/PosixDetails.java index ba6cf69f..44d8ff46 100644 --- a/projects/cadcUtil/src/ca/nrc/cadc/auth/model/PosixDetails.java +++ b/projects/cadcUtil/src/ca/nrc/cadc/auth/model/PosixDetails.java @@ -37,7 +37,7 @@ package ca.nrc.cadc.auth.model; /** * Represents the posix account details associated with a user account. */ -public class PosixDetails +public class PosixDetails implements UserDetails { private long uid; private long gid; diff --git a/projects/cadcUtil/src/ca/nrc/cadc/auth/model/User.java b/projects/cadcUtil/src/ca/nrc/cadc/auth/model/User.java index 74ab9ad6..e92232c2 100644 --- a/projects/cadcUtil/src/ca/nrc/cadc/auth/model/User.java +++ b/projects/cadcUtil/src/ca/nrc/cadc/auth/model/User.java @@ -46,8 +46,7 @@ public class User<T extends Principal> private Set<Principal> principals = new HashSet<Principal>(); - public UserDetails userDetails; - public PosixDetails posixDetails; + public Set<UserDetails> details = new HashSet<UserDetails>(); public User(final T userID) @@ -79,8 +78,7 @@ public class User<T extends Principal> { final int prime = 31; int result = 1; - result = prime * result - + ((userID == null) ? 0 : userID.hashCode()); + result = prime * result + userID.hashCode(); return result; } diff --git a/projects/cadcUtil/src/ca/nrc/cadc/auth/model/UserDetails.java b/projects/cadcUtil/src/ca/nrc/cadc/auth/model/UserDetails.java index dcede139..6720b0f8 100644 --- a/projects/cadcUtil/src/ca/nrc/cadc/auth/model/UserDetails.java +++ b/projects/cadcUtil/src/ca/nrc/cadc/auth/model/UserDetails.java @@ -34,169 +34,23 @@ package ca.nrc.cadc.auth.model; -public class UserDetails +public interface UserDetails { - private String firstName; - private String lastName; - private String email; - private String address; - private String institute; - private String city; - private String country; - - public UserDetails(String firstName, String lastName, String email, - String address, String institute, String city, String country) - { - if (firstName == null) - { - throw new IllegalArgumentException("null firstName"); - } - if (lastName == null) - { - throw new IllegalArgumentException("null lastName"); - } - if (email == null) - { - throw new IllegalArgumentException("null email"); - } - - if (address == null) - { - throw new IllegalArgumentException("null address"); - } - if (institute == null) - { - throw new IllegalArgumentException("null institute"); - } - if (city == null) - { - throw new IllegalArgumentException("null city"); - } - if (country == null) - { - throw new IllegalArgumentException("null country"); - } - this.firstName = firstName; - this.lastName = lastName; - this.email = email; - this.address = address; - this.institute = institute; - this.city = city; - this.country = country; - } - - public String getFirstName() - { - return firstName; - } - - public String getLastName() - { - return lastName; - } - - public String getEmail() - { - return email; - } - - public String getAddress() - { - return address; - } - - public String getInstitute() - { - return institute; - } - - public String getCity() - { - return city; - } - - public String getCountry() - { - return country; - } /* * (non-Javadoc) * * @see java.lang.Object#hashCode() */ - @Override - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + address.hashCode(); - result = prime * result + city.hashCode(); - result = prime * result + country.hashCode(); - result = prime * result + email.hashCode(); - result = prime * result + firstName.hashCode(); - result = prime * result + institute.hashCode(); - result = prime * result + lastName.hashCode(); - return result; - } + public int hashCode(); /* * (non-Javadoc) * * @see java.lang.Object#equals(java.lang.Object) */ - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (!(obj instanceof UserDetails)) - { - return false; - } - UserDetails other = (UserDetails) obj; - if (!firstName.equals(other.firstName)) - { - return false; - } - if (!lastName.equals(other.lastName)) - { - return false; - } - if (!email.equals(other.email)) - { - return false; - } - if (!institute.equals(other.institute)) - { - return false; - } - if (!address.equals(other.address)) - { - return false; - } - if (!city.equals(other.city)) - { - return false; - } - if (!country.equals(other.country)) - { - return false; - } - return true; - } + public boolean equals(Object obj); + + public String toString(); - @Override - public String toString() - { - return getClass().getSimpleName() + "[" + firstName + ", " - + lastName + ", " + email + ", " + address + ", " - + institute + ", " + city + ", " + country + "]"; - } -} +} \ No newline at end of file diff --git a/projects/cadcUtil/test/src/ca/nrc/cadc/auth/model/GroupTest.java b/projects/cadcUtil/test/src/ca/nrc/cadc/auth/model/GroupTest.java index 85c45dcb..3acb1a87 100644 --- a/projects/cadcUtil/test/src/ca/nrc/cadc/auth/model/GroupTest.java +++ b/projects/cadcUtil/test/src/ca/nrc/cadc/auth/model/GroupTest.java @@ -92,7 +92,7 @@ public class GroupTest assertEquals(group1.hashCode(), group2.hashCode()); assertEquals(group1,group2); - group2 = new Group("NewTestGroup", owner); + group2 = new Group("NewTestGroup-._~.", owner); assertFalse(group1.hashCode() == group2.hashCode()); assertFalse(group1.equals(group2)); @@ -125,5 +125,39 @@ public class GroupTest thrown = true; } assertTrue(thrown); + + // invavlid group IDs + thrown = false; + try + { + new Group("New/Test/Group", new User<HttpPrincipal>(new HttpPrincipal("owner"))); + } + catch(IllegalArgumentException e) + { + thrown = true; + } + assertTrue(thrown); + + thrown = false; + try + { + new Group("New%Test%Group", new User<HttpPrincipal>(new HttpPrincipal("owner"))); + } + catch(IllegalArgumentException e) + { + thrown = true; + } + assertTrue(thrown); + + thrown = false; + try + { + new Group("New\\Test\\Group", new User<HttpPrincipal>(new HttpPrincipal("owner"))); + } + catch(IllegalArgumentException e) + { + thrown = true; + } + assertTrue(thrown); } } diff --git a/projects/cadcUtil/test/src/ca/nrc/cadc/auth/model/UserTest.java b/projects/cadcUtil/test/src/ca/nrc/cadc/auth/model/UserTest.java index 547b37d4..75f0dd92 100644 --- a/projects/cadcUtil/test/src/ca/nrc/cadc/auth/model/UserTest.java +++ b/projects/cadcUtil/test/src/ca/nrc/cadc/auth/model/UserTest.java @@ -65,8 +65,8 @@ public class UserTest assertEquals(user1, user2); assertEquals(user1.hashCode(), user2.hashCode()); - user1.userDetails = new UserDetails("Joe", "Raymond", - "jr@email.com", "123 Street", "CADC", "Victoria", "CA"); + user1.details.add(new PersonalDetails("Joe", "Raymond", + "jr@email.com", "123 Street", "CADC", "Victoria", "CA")); assertEquals(user1, user2); assertEquals(user1.hashCode(), user2.hashCode()); @@ -82,8 +82,8 @@ public class UserTest assertEquals(user1, user2); assertEquals(user1.hashCode(), user2.hashCode()); - user1.posixDetails = new PosixDetails(12, 23, - "/home/myhome"); + user1.details.add(new PosixDetails(12, 23, + "/home/myhome")); assertEquals(user1, user2); assertEquals(user1.hashCode(), user2.hashCode()); @@ -93,8 +93,9 @@ public class UserTest // visual test of toString System.out.println(user1); - System.out.println(user1.userDetails); - System.out.println(user1.posixDetails); + System.out.println(new PersonalDetails("Joe", "Raymond", + "jr@email.com", "123 Street", "CADC", "Victoria", "CA")); + System.out.println(new PosixDetails(12, 23,"/home/myhome")); } @@ -115,7 +116,7 @@ public class UserTest thrown = false; try { - new UserDetails(null, "Raymond", + new PersonalDetails(null, "Raymond", "jr@email.com", "123 Street", "CADC", "Victoria", "CA"); } catch(IllegalArgumentException e) @@ -127,7 +128,7 @@ public class UserTest thrown = false; try { - new UserDetails("Joe", null, + new PersonalDetails("Joe", null, "jr@email.com", "123 Street", "CADC", "Victoria", "CA"); } catch(IllegalArgumentException e) @@ -139,7 +140,7 @@ public class UserTest thrown = false; try { - new UserDetails("Joe", "Raymond", + new PersonalDetails("Joe", "Raymond", null, "123 Street", "CADC", "Victoria", "CA"); } catch(IllegalArgumentException e) @@ -151,7 +152,7 @@ public class UserTest thrown = false; try { - new UserDetails("Joe", "Raymond", + new PersonalDetails("Joe", "Raymond", "jr@email.com", null, "CADC", "Victoria", "CA"); } catch(IllegalArgumentException e) @@ -163,7 +164,7 @@ public class UserTest thrown = false; try { - new UserDetails("Joe", "Raymond", + new PersonalDetails("Joe", "Raymond", "jr@email.com", "123 Street", null, "Victoria", "CA"); } catch(IllegalArgumentException e) @@ -175,7 +176,7 @@ public class UserTest thrown = false; try { - new UserDetails("Joe", "Raymond", + new PersonalDetails("Joe", "Raymond", "jr@email.com", "123 Street", "CADC", null, "CA"); } catch(IllegalArgumentException e) @@ -187,7 +188,7 @@ public class UserTest thrown = false; try { - new UserDetails("Joe", "Raymond", + new PersonalDetails("Joe", "Raymond", "jr@email.com", "123 Street", "CADC", "Victoria", null); } catch(IllegalArgumentException e) -- GitLab