Added PCT support, doesn't return from token endpoint yet

multiparty
Justin Richer 2016-09-22 12:05:38 -04:00
parent fcff1be114
commit f8372666e6
9 changed files with 326 additions and 4 deletions

View File

@ -0,0 +1,148 @@
/*******************************************************************************
* Copyright 2016 The MITRE Corporation
* and the MIT Internet Trust Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package org.mitre.uma.model;
import java.util.Collection;
import java.util.Date;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
/**
* @author jricher
*
*/
@Entity
@Table(name = "persisted_claims_token")
@NamedQueries ({
@NamedQuery(name = PersistedClaimsToken.QUERY_BY_VALUE, query = "select p from PersistedClaimsToken p where p.value = :" + PersistedClaimsToken.PARAM_VALUE),
})
public class PersistedClaimsToken {
public static final String QUERY_BY_VALUE = "PersistedClaimsToken.queryByValue";
public static final String PARAM_VALUE = "value";
private Long id;
private String clientId;
private Date expiration;
private Collection<Claim> claimsSupplied;
private String value;
/**
* @return the id
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
public Long getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(Long id) {
this.id = id;
}
/**
* @return the clientId
*/
@Basic
@Column(name = "client_id")
public String getClientId() {
return clientId;
}
/**
* @param clientId the clientId to set
*/
public void setClientId(String clientId) {
this.clientId = clientId;
}
/**
* @return the expiration
*/
@Basic
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "expiration")
public Date getExpiration() {
return expiration;
}
/**
* @param expiration the expiration to set
*/
public void setExpiration(Date expiration) {
this.expiration = expiration;
}
/**
* @return the claimsSupplied
*/
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinTable(
name = "claim_to_permission_ticket",
joinColumns = @JoinColumn(name = "permission_ticket_id"),
inverseJoinColumns = @JoinColumn(name = "claim_id")
)
public Collection<Claim> getClaimsSupplied() {
return claimsSupplied;
}
/**
* @param claimsSupplied the claimsSupplied to set
*/
public void setClaimsSupplied(Collection<Claim> claimsSupplied) {
this.claimsSupplied = claimsSupplied;
}
/**
* @return the value
*/
@Basic
@Column(name = "token_value")
public String getValue() {
return value;
}
/**
* @param value the value to set
*/
public void setValue(String value) {
this.value = value;
}
}

View File

@ -0,0 +1,41 @@
/*******************************************************************************
* Copyright 2016 The MITRE Corporation
* and the MIT Internet Trust Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package org.mitre.uma.repository;
import org.mitre.uma.model.PersistedClaimsToken;
/**
* @author jricher
*
*/
public interface PersistedClaimsTokenRepository {
/**
* @param pctValue
* @return
*/
PersistedClaimsToken getByValue(String pctValue);
/**
* @param pct
* @return
*/
PersistedClaimsToken save(PersistedClaimsToken pct);
}

View File

@ -19,6 +19,7 @@ package org.mitre.uma.service;
import org.mitre.uma.model.ClaimProcessingResult;
import org.mitre.uma.model.PermissionTicket;
import org.mitre.uma.model.PersistedClaimsToken;
import org.mitre.uma.model.ResourceSet;
/**
@ -40,6 +41,6 @@ public interface ClaimsProcessingService {
* @param ticket the supplied claims to test
* @return the result of the claims processing action
*/
public ClaimProcessingResult claimsAreSatisfied(ResourceSet rs, PermissionTicket ticket);
public ClaimProcessingResult claimsAreSatisfied(ResourceSet rs, PermissionTicket ticket, PersistedClaimsToken pct);
}

View File

@ -19,6 +19,7 @@ package org.mitre.uma.service;
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
import org.mitre.uma.model.PermissionTicket;
import org.mitre.uma.model.PersistedClaimsToken;
import org.mitre.uma.model.Policy;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
@ -36,4 +37,12 @@ public interface UmaTokenService {
*/
public OAuth2AccessTokenEntity createRequestingPartyToken(OAuth2Authentication o2auth, PermissionTicket ticket, Policy policy);
/**
* @param pctValue
* @return
*/
public PersistedClaimsToken getPersistedClaimsTokenByValue(String pctValue);
public PersistedClaimsToken savePersistedClaimsToken(PersistedClaimsToken pct);
}

View File

@ -330,6 +330,17 @@ CREATE TABLE IF NOT EXISTS claim_to_permission_ticket (
claim_id BIGINT NOT NULL
);
CREATE TABLE IF NOT EXISTS claim_to_pct (
pct_id BIGINT NOT NULL,
claim_id BIGINT NOT NULL
);
CREATE TABLE IF NOT EXISTS persisted_claims_token (
id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY,
client_id VARCHAR(256),
token_value VARCHAR(2048)
);
CREATE TABLE IF NOT EXISTS policy (
id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY,
name VARCHAR(1024),

View File

@ -0,0 +1,62 @@
/*******************************************************************************
* Copyright 2016 The MITRE Corporation
* and the MIT Internet Trust Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package org.mitre.uma.repository.impl;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import org.mitre.uma.model.PersistedClaimsToken;
import org.mitre.uma.repository.PersistedClaimsTokenRepository;
import org.mitre.util.jpa.JpaUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
/**
* @author jricher
*
*/
@Repository("persistedClaimsTokenRepository")
public class JpaPersistedClaimsTokenRepository implements PersistedClaimsTokenRepository {
@PersistenceContext(unitName="defaultPersistenceUnit")
private EntityManager em;
private static Logger logger = LoggerFactory.getLogger(JpaPersistedClaimsTokenRepository.class);
/* (non-Javadoc)
* @see org.mitre.uma.repository.PersistedClaimsTokenRepository#getPersistedClaimsTokenByValue(java.lang.String)
*/
@Override
public PersistedClaimsToken getByValue(String pctValue) {
TypedQuery<PersistedClaimsToken> query = em.createNamedQuery(PersistedClaimsToken.QUERY_BY_VALUE, PersistedClaimsToken.class);
query.setParameter(PersistedClaimsToken.PARAM_VALUE, pctValue);
return JpaUtil.getSingleResult(query.getResultList());
}
/* (non-Javadoc)
* @see org.mitre.uma.repository.PersistedClaimsTokenRepository#savePersistedClaimsToken(org.mitre.uma.model.PersistedClaimsToken)
*/
@Override
@Transactional(value="defaultTransactionManager")
public PersistedClaimsToken save(PersistedClaimsToken pct) {
return JpaUtil.saveOrUpdate(pct.getId(), em, pct);
}
}

View File

@ -32,7 +32,9 @@ import org.mitre.oauth2.service.OAuth2TokenEntityService;
import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
import org.mitre.uma.model.Permission;
import org.mitre.uma.model.PermissionTicket;
import org.mitre.uma.model.PersistedClaimsToken;
import org.mitre.uma.model.Policy;
import org.mitre.uma.repository.PersistedClaimsTokenRepository;
import org.mitre.uma.service.UmaTokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
@ -66,6 +68,9 @@ public class DefaultUmaTokenService implements UmaTokenService {
@Autowired
private JWTSigningAndValidationService jwtService;
@Autowired
private PersistedClaimsTokenRepository pctRepository;
@Override
@ -118,4 +123,23 @@ public class DefaultUmaTokenService implements UmaTokenService {
return token;
}
/* (non-Javadoc)
* @see org.mitre.uma.service.UmaTokenService#getPersistedClaimsTokenByValue(java.lang.String)
*/
@Override
public PersistedClaimsToken getPersistedClaimsTokenByValue(String pctValue) {
return pctRepository.getByValue(pctValue);
}
/* (non-Javadoc)
* @see org.mitre.uma.service.UmaTokenService#savePersistedClaimsToken(org.mitre.uma.model.PersistedClaimsToken)
*/
@Override
public PersistedClaimsToken savePersistedClaimsToken(PersistedClaimsToken pct) {
return pctRepository.save(pct);
}
}

View File

@ -23,6 +23,7 @@ import java.util.HashSet;
import org.mitre.uma.model.Claim;
import org.mitre.uma.model.ClaimProcessingResult;
import org.mitre.uma.model.PermissionTicket;
import org.mitre.uma.model.PersistedClaimsToken;
import org.mitre.uma.model.Policy;
import org.mitre.uma.model.ResourceSet;
import org.mitre.uma.service.ClaimsProcessingService;
@ -42,10 +43,15 @@ public class MatchAllClaimsOnAnyPolicy implements ClaimsProcessingService {
* @see org.mitre.uma.service.ClaimsProcessingService#claimsAreSatisfied(java.util.Collection, java.util.Collection)
*/
@Override
public ClaimProcessingResult claimsAreSatisfied(ResourceSet rs, PermissionTicket ticket) {
public ClaimProcessingResult claimsAreSatisfied(ResourceSet rs, PermissionTicket ticket, PersistedClaimsToken pct) {
Collection<Claim> allUnmatched = new HashSet<>();
Collection<Claim> claimsSupplied = new HashSet<>(ticket.getClaimsSupplied()); // copy the claims out of the ticket
if (pct != null && pct.getClaimsSupplied() != null) {
// add the claims from the PCT if available
claimsSupplied.addAll(pct.getClaimsSupplied());
}
for (Policy policy : rs.getPolicies()) {
Collection<Claim> unmatched = checkIndividualClaims(policy.getClaimsRequired(), ticket.getClaimsSupplied());
Collection<Claim> unmatched = checkIndividualClaims(policy.getClaimsRequired(), claimsSupplied);
if (unmatched.isEmpty()) {
// we found something that's satisfied the claims, let's go with it!
return new ClaimProcessingResult(policy);

View File

@ -42,6 +42,7 @@ import org.mitre.uma.model.Claim;
import org.mitre.uma.model.ClaimProcessingResult;
import org.mitre.uma.model.Permission;
import org.mitre.uma.model.PermissionTicket;
import org.mitre.uma.model.PersistedClaimsToken;
import org.mitre.uma.model.ResourceSet;
import org.mitre.uma.service.ClaimsProcessingService;
import org.mitre.uma.service.PermissionService;
@ -134,6 +135,12 @@ public class RequestingPartyTokenGranter extends AbstractTokenGranter {
if (!Strings.isNullOrEmpty(rptValue)) {
incomingRpt = tokenService.readAccessToken(rptValue);
}
String pctValue = tokenRequest.getRequestParameters().get("pct");
PersistedClaimsToken pct = null;
if (!Strings.isNullOrEmpty(pctValue)) {
pct = umaTokenService.getPersistedClaimsTokenByValue(pctValue);
}
if (ticket != null) {
// found the ticket, see if it's any good
@ -147,7 +154,7 @@ public class RequestingPartyTokenGranter extends AbstractTokenGranter {
} else {
// claims weren't empty or missing, we need to check against what we have
ClaimProcessingResult result = claimsProcessingService.claimsAreSatisfied(rs, ticket);
ClaimProcessingResult result = claimsProcessingService.claimsAreSatisfied(rs, ticket, pct);
if (result.isSatisfied()) {
@ -236,7 +243,20 @@ public class RequestingPartyTokenGranter extends AbstractTokenGranter {
if (incomingRpt != null) {
tokenService.revokeAccessToken(incomingRpt);
}
// create a PCT
PersistedClaimsToken newPct = new PersistedClaimsToken();
newPct.setClientId(client.getClientId());
newPct.setExpiration(null); // TODO: we'll make these not expire for now, should be configurable per-client like other token lifetimes
newPct.setValue(UUID.randomUUID().toString()); // make a random value
HashSet<Claim> claimsSupplied = new HashSet<>();
claimsSupplied.addAll(ticket.getClaimsSupplied());
if (pct != null && pct.getClaimsSupplied() != null) {
claimsSupplied.addAll(pct.getClaimsSupplied());
}
newPct.setClaimsSupplied(claimsSupplied);
// TODO: figure out how to return the PCT in the token response
return token;
} else {