added transient structured value to system scope, added scope matcher function to scope service

pull/516/head
Justin Richer 2013-08-30 14:41:51 -04:00
parent 1ef18a3a93
commit 72f0ab631d
4 changed files with 223 additions and 134 deletions

View File

@ -28,6 +28,7 @@ import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Transient;
/**
* @author jricher
@ -49,6 +50,7 @@ public class SystemScope {
private boolean defaultScope = false; // is this a default scope for newly-registered clients?
private boolean structured = false; // is this a default scope for newly-registered clients?
private String structuredParamDescription;
private String structuredValue;
/**
* Make a blank system scope with no value
@ -64,6 +66,7 @@ public class SystemScope {
public SystemScope(String value) {
this.value = value;
}
/**
* @return the id
*/
@ -161,8 +164,11 @@ public class SystemScope {
return structured;
}
public void setIsStructured(boolean isStructured) {
this.structured = isStructured;
/**
* @param structured the structured to set
*/
public void setStructured(boolean structured) {
this.structured = structured;
}
@Basic
@ -179,81 +185,117 @@ public class SystemScope {
}
/**
* @return the structuredValue
*/
@Transient // we don't save the value of a system scope separately
public String getStructuredValue() {
return structuredValue;
}
/**
* @param structuredValue the structuredValue to set
*/
public void setStructuredValue(String structuredValue) {
this.structuredValue = structuredValue;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (allowDynReg ? 1231 : 1237);
result = prime * result + (defaultScope ? 1231 : 1237);
result = prime * result + (structured ? 1231 : 1237);
result = prime * result + ((description == null) ? 0 : description.hashCode());
result = prime * result + ((icon == null) ? 0 : icon.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (allowDynReg ? 1231 : 1237);
result = prime * result + (defaultScope ? 1231 : 1237);
result = prime * result + ((description == null) ? 0 : description.hashCode());
result = prime * result + ((icon == null) ? 0 : icon.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + (structured ? 1231 : 1237);
result = prime * result + ((structuredParamDescription == null) ? 0 : structuredParamDescription.hashCode());
result = prime * result + ((structuredValue == null) ? 0 : structuredValue.hashCode());
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
/* (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 (getClass() != obj.getClass()) {
return false;
}
SystemScope other = (SystemScope) obj;
if (allowDynReg != other.allowDynReg) {
return false;
}
if (defaultScope != other.defaultScope) {
return false;
}
if (structured != other.structured) {
return false;
}
if (description == null) {
if (other.description != null) {
return false;
}
} else if (!description.equals(other.description)) {
return false;
}
if (icon == null) {
if (other.icon != null) {
return false;
}
} else if (!icon.equals(other.icon)) {
return false;
}
if (id == null) {
if (other.id != null) {
return false;
}
} else if (!id.equals(other.id)) {
return false;
}
if (value == null) {
if (other.value != null) {
return false;
}
} else if (!value.equals(other.value)) {
return false;
}
return true;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof SystemScope)) {
return false;
}
SystemScope other = (SystemScope) obj;
if (allowDynReg != other.allowDynReg) {
return false;
}
if (defaultScope != other.defaultScope) {
return false;
}
if (description == null) {
if (other.description != null) {
return false;
}
} else if (!description.equals(other.description)) {
return false;
}
if (icon == null) {
if (other.icon != null) {
return false;
}
} else if (!icon.equals(other.icon)) {
return false;
}
if (id == null) {
if (other.id != null) {
return false;
}
} else if (!id.equals(other.id)) {
return false;
}
if (structured != other.structured) {
return false;
}
if (structuredParamDescription == null) {
if (other.structuredParamDescription != null) {
return false;
}
} else if (!structuredParamDescription.equals(other.structuredParamDescription)) {
return false;
}
if (structuredValue == null) {
if (other.structuredValue != null) {
return false;
}
} else if (!structuredValue.equals(other.structuredValue)) {
return false;
}
if (value == null) {
if (other.value != null) {
return false;
}
} else if (!value.equals(other.value)) {
return false;
}
return true;
}
@Override
public String toString() {
return "SystemScope [value=" + value + ", description=" + description + ", icon=" + icon + ", allowDynReg=" + allowDynReg + ", defaultScope=" + defaultScope + ", isStructured=" + structured + "]";
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "SystemScope [id=" + id + ", value=" + value + ", description=" + description + ", icon=" + icon + ", allowDynReg=" + allowDynReg + ", defaultScope=" + defaultScope + ", structured=" + structured + ", structuredParamDescription=" + structuredParamDescription + ", structuredValue="
+ structuredValue + "]";
}
}

View File

@ -66,10 +66,13 @@ public interface SystemScopeService {
*/
public Set<String> toStrings(Set<SystemScope> scope);
public String baseScopeString(String value);
public Map<String, String> structuredScopeParameters(Set<String> scope);
public SystemScope toStructuredScope(String s);
/**
* Test whether the scopes in both sets are compatible, with special
* processing for structured scopes. All scopes in "actual" must exist in
* "expected". If a scope in "expected" is structured and has a value, it
* must be matched exactly by its corresponding scope in "actual". If a
* scope in "expected" is structured but has no value, it may be matched by
* a scope with or without a value in "actual".
*/
public boolean scopesMatch(Set<String> expected, Set<String> actual);
}

View File

@ -19,11 +19,9 @@
*/
package org.mitre.oauth2.service.impl;
import java.util.HashMap;
import java.util.Map;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
import org.mitre.oauth2.model.SystemScope;
import org.mitre.oauth2.repository.SystemScopeRepository;
@ -35,8 +33,9 @@ import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.Collections2;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
/**
@ -67,18 +66,26 @@ public class DefaultSystemScopeService implements SystemScopeService {
private Function<String, SystemScope> stringToSystemScope = new Function<String, SystemScope>() {
@Override
public SystemScope apply(String input) {
input = baseScopeString(input);
if (input == null) {
if (Strings.isNullOrEmpty(input)) {
return null;
} else {
SystemScope s = getByValue(input);
if (s != null) {
// get the real scope if it's available
return s;
} else {
List<String> parts = parseStructuredScopeValue(input);
String base = parts.get(0); // the first part is the base
// get the real scope if it's available
SystemScope s = getByValue(base);
if (s == null) {
// make a fake one otherwise
return new SystemScope(input);
s = new SystemScope(base);
if (parts.size() > 1) {
s.setStructured(true);
}
}
if (s.isStructured() && parts.size() > 1) {
s.setStructuredValue(parts.get(1));
}
return s;
}
}
};
@ -175,52 +182,48 @@ public class DefaultSystemScopeService implements SystemScopeService {
}
}
private String[] scopeParts(String value){
return Iterables.toArray(
Splitter.on(":").split(value),
String.class);
// parse a structured scope string into its components
private List<String> parseStructuredScopeValue(String value) {
return Lists.newArrayList(Splitter.on(":").split(value));
}
@Override
public String baseScopeString(String value) {
SystemScope s = toStructuredScope(value);
if (s != null) {
return s.getValue();
}
return value;
}
/* (non-Javadoc)
* @see org.mitre.oauth2.service.SystemScopeService#scopesMatch(java.util.Set, java.util.Set)
*/
@Override
public boolean scopesMatch(Set<String> expected, Set<String> actual) {
@Override
public SystemScope toStructuredScope(String value) {
String[] scopeParts = scopeParts(value);
String baseScope = value;
if (scopeParts.length == 2) {
baseScope = scopeParts[0];
}
SystemScope s = repository.getByValue(baseScope);
if (s != null && s.isStructured()) {
return s;
}
Set<SystemScope> ex = fromStrings(expected);
Set<SystemScope> act = fromStrings(actual);
return null;
}
for (SystemScope actScope : act) {
// first check to see if there's an exact match
if (!ex.contains(actScope)) {
// we didn't find an exact match
if (actScope.isStructured() && !Strings.isNullOrEmpty(actScope.getStructuredValue())) {
// if we didn't get an exact match but the actual scope is structured, we need to check further
@Override
public Map<String, String> structuredScopeParameters(Set<String> scopes) {
HashMap<String, String> ret = new HashMap<String, String>();
// first, find the "base" scope for this
SystemScope base = getByValue(actScope.getValue());
if (!ex.contains(base)) {
// if the expected doesn't contain the base scope, fail
return false;
} else {
// we did find an exact match, need to check the rest
}
} else {
// the scope wasn't structured, fail now
return false;
}
} else {
// if we did find an exact match, we need to check the rest
}
}
for (String s : scopes){
SystemScope structured = toStructuredScope(s);
if (structured != null){
String[] scopeParts = scopeParts(s);
if (scopeParts.length == 2){
ret.put(scopeParts[0], scopeParts[1]);
}
}
}
// if we got all the way down here, the setup passed
return true;
return ret;
}
}

View File

@ -26,7 +26,9 @@ import org.mitre.oauth2.repository.SystemScopeRepository;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import com.google.common.collect.Sets;
@ -147,4 +149,43 @@ public class TestDefaultSystemScopeService {
assertThat(service.toStrings(allScopes), equalTo(allScopeStrings));
}
@Test
public void scopesMatch() {
Set<String> expected = Sets.newHashSet("foo", "bar", "baz");
Set<String> actualGood = Sets.newHashSet("foo", "baz", "bar");
Set<String> actualGood2 = Sets.newHashSet("foo", "bar");
Set<String> actualBad = Sets.newHashSet("foo", "bob", "bar");
// same scopes, different order
assertThat(service.scopesMatch(expected, actualGood), is(true));
// subset
assertThat(service.scopesMatch(expected, actualGood2), is(true));
// extra scope (fail)
assertThat(service.scopesMatch(expected, actualBad), is(false));
}
@Test
public void scopesMatch_structured() {
Set<String> expected = Sets.newHashSet("foo", "bar", "baz");
Set<String> actualGood = Sets.newHashSet("foo:value", "baz", "bar");
Set<String> actualBad = Sets.newHashSet("foo:value", "bar:value");
// note: we have to use "thenAnswer" here to mimic the repository not serializing the structuredValue field
Mockito.when(repository.getByValue("foo")).thenAnswer(new Answer<SystemScope>() {
@Override
public SystemScope answer(InvocationOnMock invocation) throws Throwable {
SystemScope foo = new SystemScope("foo");
foo.setStructured(true);
return foo;
}
});
assertThat(service.scopesMatch(expected, actualGood), is(true));
assertThat(service.scopesMatch(expected, actualBad), is(false));
}
}