allow extension points for JSON validation parsing. add filter and validator
This commit is contained in:
parent
1fc896c458
commit
5152f40be9
|
|
@ -35,6 +35,11 @@
|
|||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import org.jasig.cas.client.util.XmlUtils;
|
|||
* @author Scott Battaglia
|
||||
* @since 3.1
|
||||
*/
|
||||
public class Cas20ProxyTicketValidator extends Cas20ServiceTicketValidator {
|
||||
public class Cas20ProxyTicketValidator extends Cas20ServiceTicketValidator implements ProxyTicketValidator {
|
||||
|
||||
private boolean acceptAnyProxy;
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ public class Cas20ProxyTicketValidator extends Cas20ServiceTicketValidator {
|
|||
);
|
||||
}
|
||||
// this means there was nothing in the proxy chain, which is okay
|
||||
if ((this.allowEmptyProxyChain && proxies.isEmpty())) {
|
||||
if (this.allowEmptyProxyChain && proxies.isEmpty()) {
|
||||
logger.debug("Found an empty proxy chain, permitted by client configuration");
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ public class Cas20ServiceTicketValidator extends AbstractCasProtocolUrlBasedTick
|
|||
return "serviceValidate";
|
||||
}
|
||||
|
||||
protected final Assertion parseResponseFromServer(final String response) throws TicketValidationException {
|
||||
protected Assertion parseResponseFromServer(final String response) throws TicketValidationException {
|
||||
final String error = parseAuthenticationFailureFromResponse(response);
|
||||
|
||||
if (CommonUtils.isNotBlank(error)) {
|
||||
|
|
|
|||
|
|
@ -1,41 +0,0 @@
|
|||
package org.jasig.cas.client.validation;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This is {@link Cas30JsonServiceTicketValidator}.
|
||||
*
|
||||
* @author Misagh Moayyed
|
||||
*/
|
||||
public class Cas30JsonServiceTicketValidator extends Cas30ProxyTicketValidator {
|
||||
public Cas30JsonServiceTicketValidator(final String casServerUrlPrefix) {
|
||||
super(casServerUrlPrefix);
|
||||
getCustomParameters().put("format", "JSON");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> parseProxiesFromResponse(final String response) {
|
||||
return super.parseProxiesFromResponse(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String parseProxyGrantingTicketFromResponse(final String response) {
|
||||
return super.parseProxyGrantingTicketFromResponse(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String parsePrincipalFromResponse(final String response) {
|
||||
return super.parsePrincipalFromResponse(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String parseAuthenticationFailureFromResponse(final String response) {
|
||||
return super.parseAuthenticationFailureFromResponse(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> extractCustomAttributes(final String xml) {
|
||||
return super.extractCustomAttributes(xml);
|
||||
}
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@ package org.jasig.cas.client.validation;
|
|||
*/
|
||||
public class Cas30ServiceTicketValidator extends Cas20ServiceTicketValidator {
|
||||
|
||||
public Cas30ServiceTicketValidator(String casServerUrlPrefix) {
|
||||
public Cas30ServiceTicketValidator(final String casServerUrlPrefix) {
|
||||
super(casServerUrlPrefix);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,9 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jasig.cas.client.validation;
|
||||
package org.jasig.cas.client.validation.json;
|
||||
|
||||
import org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter;
|
||||
|
||||
/**
|
||||
* Creates either a Cas30JsonServiceTicketValidator to validate tickets.
|
||||
|
|
@ -28,6 +30,6 @@ public class Cas30JsonProxyReceivingTicketValidationFilter extends Cas30ProxyRec
|
|||
public Cas30JsonProxyReceivingTicketValidationFilter() {
|
||||
super();
|
||||
this.defaultServiceTicketValidatorClass = Cas30JsonServiceTicketValidator.class;
|
||||
this.defaultProxyTicketValidatorClass = Cas30JsonServiceTicketValidator.class;
|
||||
this.defaultProxyTicketValidatorClass = Cas30JsonProxyTicketValidator.class;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package org.jasig.cas.client.validation.json;
|
||||
|
||||
import org.jasig.cas.client.validation.Assertion;
|
||||
import org.jasig.cas.client.validation.Cas30ProxyTicketValidator;
|
||||
import org.jasig.cas.client.validation.ProxyTicketValidator;
|
||||
import org.jasig.cas.client.validation.TicketValidationException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This is {@link Cas30JsonProxyTicketValidator} that attempts to parse the CAS validation response
|
||||
* as JSON. Very similar to {@link Cas30JsonServiceTicketValidator}, it also honors proxies as the name suggests.
|
||||
*
|
||||
* @author Misagh Moayyed
|
||||
*/
|
||||
public class Cas30JsonProxyTicketValidator extends Cas30JsonServiceTicketValidator implements ProxyTicketValidator {
|
||||
public Cas30JsonProxyTicketValidator(final String casServerUrlPrefix) {
|
||||
super(casServerUrlPrefix);
|
||||
getCustomParameters().put("format", "JSON");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Assertion parseResponseFromServer(final String response) throws TicketValidationException {
|
||||
return super.parseResponseFromServer(response);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package org.jasig.cas.client.validation.json;
|
||||
|
||||
import org.jasig.cas.client.authentication.AttributePrincipal;
|
||||
import org.jasig.cas.client.authentication.AttributePrincipalImpl;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.jasig.cas.client.validation.Assertion;
|
||||
import org.jasig.cas.client.validation.AssertionImpl;
|
||||
import org.jasig.cas.client.validation.Cas30ServiceTicketValidator;
|
||||
import org.jasig.cas.client.validation.TicketValidationException;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This is {@link Cas30JsonServiceTicketValidator} that attempts to parse the CAS validation response
|
||||
* as JSON. If the response is not formatted as JSON, it shall fallback to the XML default syntax.
|
||||
* The JSON response provides advantages in terms of naming and parsing CAS attributes that have special
|
||||
* names that otherwise may not be encoded as XML, such as the invalid {@code <cas:special:attribute>value</cas:special:attribute>}
|
||||
*
|
||||
* @author Misagh Moayyed
|
||||
*/
|
||||
public class Cas30JsonServiceTicketValidator extends Cas30ServiceTicketValidator {
|
||||
|
||||
public Cas30JsonServiceTicketValidator(final String casServerUrlPrefix) {
|
||||
super(casServerUrlPrefix);
|
||||
getCustomParameters().put("format", "JSON");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Assertion parseResponseFromServer(final String response) throws TicketValidationException {
|
||||
final TicketValidationJsonResponse json = new JsonValidationResponseParser().parse(response);
|
||||
final String proxyGrantingTicketIou = json.getAuthenticationSuccess().getProxyGrantingTicket();
|
||||
final String proxyGrantingTicket;
|
||||
if (CommonUtils.isBlank(proxyGrantingTicketIou) || getProxyGrantingTicketStorage() == null) {
|
||||
proxyGrantingTicket = null;
|
||||
} else {
|
||||
proxyGrantingTicket = getProxyGrantingTicketStorage().retrieve(proxyGrantingTicketIou);
|
||||
}
|
||||
|
||||
final Assertion assertion;
|
||||
final Map<String, Object> attributes = json.getAuthenticationSuccess().getAttributes();
|
||||
final String principal = json.getAuthenticationSuccess().getUser();
|
||||
if (CommonUtils.isNotBlank(proxyGrantingTicket)) {
|
||||
final AttributePrincipal attributePrincipal = new AttributePrincipalImpl(principal, attributes,
|
||||
proxyGrantingTicket, getProxyRetriever());
|
||||
assertion = new AssertionImpl(attributePrincipal);
|
||||
} else {
|
||||
assertion = new AssertionImpl(new AttributePrincipalImpl(principal, attributes));
|
||||
}
|
||||
return assertion;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package org.jasig.cas.client.validation.json;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.jasig.cas.client.validation.TicketValidationException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This is {@link JsonValidationResponseParser}.
|
||||
*
|
||||
* @author Misagh Moayyed
|
||||
*/
|
||||
final class JsonValidationResponseParser {
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
public JsonValidationResponseParser() {
|
||||
this.objectMapper = new ObjectMapper();
|
||||
this.objectMapper.findAndRegisterModules();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public TicketValidationJsonResponse parse(final String response) throws TicketValidationException {
|
||||
try {
|
||||
final TicketValidationJsonResponse json = this.objectMapper.readValue(response, TicketValidationJsonResponse.class);
|
||||
|
||||
if (json == null || json.getAuthenticationFailure() != null && json.getAuthenticationSuccess() != null) {
|
||||
throw new TicketValidationException("Invalid JSON response; either the response is empty or it indicates both a success "
|
||||
+ "and a failure event, which is indicative of a server error. The actual response is " + response);
|
||||
}
|
||||
|
||||
if (json.getAuthenticationFailure() != null) {
|
||||
final String error = json.getAuthenticationFailure().getDescription()
|
||||
+ " - " + json.getAuthenticationFailure().getDescription();
|
||||
throw new TicketValidationException(error);
|
||||
}
|
||||
|
||||
final String principal = json.getAuthenticationSuccess().getUser();
|
||||
if (CommonUtils.isEmpty(principal)) {
|
||||
throw new TicketValidationException("No principal was found in the response from the CAS server.");
|
||||
}
|
||||
return json;
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException("Unable to parse JSON validation response", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
package org.jasig.cas.client.validation.json;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This is {@link TicketValidationJsonResponse}.
|
||||
*
|
||||
* @author Misagh Moayyed
|
||||
*/
|
||||
final class TicketValidationJsonResponse {
|
||||
private CasServiceResponseAuthenticationFailure authenticationFailure;
|
||||
private CasServiceResponseAuthenticationSuccess authenticationSuccess;
|
||||
|
||||
public CasServiceResponseAuthenticationFailure getAuthenticationFailure() {
|
||||
return this.authenticationFailure;
|
||||
}
|
||||
|
||||
public void setAuthenticationFailure(final CasServiceResponseAuthenticationFailure authenticationFailure) {
|
||||
this.authenticationFailure = authenticationFailure;
|
||||
}
|
||||
|
||||
public CasServiceResponseAuthenticationSuccess getAuthenticationSuccess() {
|
||||
return this.authenticationSuccess;
|
||||
}
|
||||
|
||||
public void setAuthenticationSuccess(final CasServiceResponseAuthenticationSuccess authenticationSuccess) {
|
||||
this.authenticationSuccess = authenticationSuccess;
|
||||
}
|
||||
|
||||
static class CasServiceResponseAuthenticationSuccess {
|
||||
private String user;
|
||||
private String proxyGrantingTicket;
|
||||
private List proxies;
|
||||
private Map attributes;
|
||||
|
||||
public String getUser() {
|
||||
return this.user;
|
||||
}
|
||||
|
||||
public void setUser(final String user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public String getProxyGrantingTicket() {
|
||||
return this.proxyGrantingTicket;
|
||||
}
|
||||
|
||||
public void setProxyGrantingTicket(final String proxyGrantingTicket) {
|
||||
this.proxyGrantingTicket = proxyGrantingTicket;
|
||||
}
|
||||
|
||||
public List getProxies() {
|
||||
return this.proxies;
|
||||
}
|
||||
|
||||
public void setProxies(final List proxies) {
|
||||
this.proxies = proxies;
|
||||
}
|
||||
|
||||
public Map getAttributes() {
|
||||
return this.attributes;
|
||||
}
|
||||
|
||||
public void setAttributes(final Map attributes) {
|
||||
this.attributes = attributes;
|
||||
}
|
||||
}
|
||||
|
||||
static class CasServiceResponseAuthenticationFailure {
|
||||
private String code;
|
||||
private String description;
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public void setCode(final String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public void setDescription(final String description) {
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
6
pom.xml
6
pom.xml
|
|
@ -206,6 +206,11 @@
|
|||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
|
@ -261,5 +266,6 @@
|
|||
<ehcache.version>2.2.0</ehcache.version>
|
||||
<clover.version>3.0.2</clover.version>
|
||||
<slf4j.version>1.7.1</slf4j.version>
|
||||
<jackson.version>2.8.8.1</jackson.version>
|
||||
</properties>
|
||||
</project>
|
||||
|
|
|
|||
Loading…
Reference in New Issue