Merge branch 'user-approval-handler-updated-rebase'

pull/165/merge
Amanda Anganes 2012-08-06 16:30:03 -04:00
commit a061e64abf
22 changed files with 414 additions and 209 deletions

View File

@ -19,6 +19,7 @@ import java.util.Date;
import java.util.Set; import java.util.Set;
import javax.persistence.Basic; import javax.persistence.Basic;
import javax.persistence.CollectionTable;
import javax.persistence.ElementCollection; import javax.persistence.ElementCollection;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.FetchType; import javax.persistence.FetchType;
@ -31,15 +32,14 @@ import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery; import javax.persistence.NamedQuery;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.Temporal; import javax.persistence.Temporal;
import javax.persistence.Transient;
import org.mitre.oauth2.model.ClientDetailsEntity;
@Entity @Entity
@Table(name="approvedsite") @Table(name="approvedsite")
@NamedQueries({ @NamedQueries({
@NamedQuery(name = "ApprovedSite.getAll", query = "select a from ApprovedSite a"), @NamedQuery(name = "ApprovedSite.getAll", query = "select a from ApprovedSite a"),
@NamedQuery(name = "ApprovedSite.getByUserInfo", query = "select a from ApprovedSite a where a.userInfo = :approvedSiteUserInfo"), @NamedQuery(name = "ApprovedSite.getByUserId", query = "select a from ApprovedSite a where a.userId = :userId"),
@NamedQuery(name = "ApprovedSite.getByClientDetails", query = "select a from ApprovedSite a where a.clientDetails = :approvedSiteClientDetails") @NamedQuery(name = "ApprovedSite.getByClientIdAndUserId", query = "select a from ApprovedSite a where a.clientId = :clientId and a.userId = :userId")
}) })
public class ApprovedSite { public class ApprovedSite {
@ -47,10 +47,10 @@ public class ApprovedSite {
private Long id; private Long id;
// which user made the approval // which user made the approval
private String userInfo; private String userId;
// which OAuth2 client is this tied to // which OAuth2 client is this tied to
private ClientDetailsEntity clientDetails; private String clientId;
// when was this first approved? // when was this first approved?
private Date creationDate; private Date creationDate;
@ -65,6 +65,9 @@ public class ApprovedSite {
// this should include all information for what data to access // this should include all information for what data to access
private Set<String> allowedScopes; private Set<String> allowedScopes;
// If this AP is a WS, link to the WS
private WhitelistedSite whitelistedSite;
// TODO: should we store the OAuth2 tokens and IdTokens here? // TODO: should we store the OAuth2 tokens and IdTokens here?
/** /**
@ -94,31 +97,30 @@ public class ApprovedSite {
* @return the userInfo * @return the userInfo
*/ */
@Basic @Basic
public String getUserInfo() { public String getUserId() {
return userInfo; return userId;
} }
/** /**
* @param userInfo the userInfo to set * @param userInfo the userInfo to set
*/ */
public void setUserInfo(String userInfo) { public void setUserId(String userId) {
this.userInfo = userInfo; this.userId = userId;
} }
/** /**
* @return the clientDetails * @return the clientId
*/ */
@ManyToOne @Basic
@JoinColumn(name="clientdetails_id") public String getClientId() {
public ClientDetailsEntity getClientDetails() { return clientId;
return clientDetails;
} }
/** /**
* @param clientDetails the clientDetails to set * @param clientId the clientId to set
*/ */
public void setClientDetails(ClientDetailsEntity clientDetails) { public void setClientId(String clientId) {
this.clientDetails = clientDetails; this.clientId = clientId;
} }
/** /**
@ -157,6 +159,10 @@ public class ApprovedSite {
* @return the allowedScopes * @return the allowedScopes
*/ */
@ElementCollection(fetch = FetchType.EAGER) @ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(
name="allowed_scopes",
joinColumns=@JoinColumn(name="owner_id")
)
public Set<String> getAllowedScopes() { public Set<String> getAllowedScopes() {
return allowedScopes; return allowedScopes;
} }
@ -184,6 +190,24 @@ public class ApprovedSite {
this.timeoutDate = timeoutDate; this.timeoutDate = timeoutDate;
} }
/**
* Does this AP entry correspond to a WS?
* @return
*/
@Transient
public Boolean getIsWhitelisted() {
return (whitelistedSite != null);
}
@ManyToOne
@JoinColumn(name="whitelistedsite_id")
public WhitelistedSite getWhitelistedSite() {
return whitelistedSite;
}
public void setWhitelistedSite(WhitelistedSite whitelistedSite) {
this.whitelistedSite = whitelistedSite;
}
} }

View File

@ -18,6 +18,7 @@ package org.mitre.openid.connect.model;
import java.util.Set; import java.util.Set;
import javax.persistence.Basic; import javax.persistence.Basic;
import javax.persistence.CollectionTable;
import javax.persistence.ElementCollection; import javax.persistence.ElementCollection;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.FetchType; import javax.persistence.FetchType;
@ -25,34 +26,33 @@ import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType; import javax.persistence.GenerationType;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries; import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery; import javax.persistence.NamedQuery;
import javax.persistence.Table; import javax.persistence.Table;
import org.mitre.oauth2.model.ClientDetailsEntity;
/** /**
* Indicator that login to a site should be automatically granted * Indicator that login to a site should be automatically granted
* without user interaction. * without user interaction.
* @author jricher * @author jricher, aanganes
* *
*/ */
@Entity @Entity
@Table(name="whitelistedsite") @Table(name="whitelistedsite")
@NamedQueries({ @NamedQueries({
@NamedQuery(name = "WhitelistedSite.getAll", query = "select w from WhitelistedSite w") @NamedQuery(name = "WhitelistedSite.getAll", query = "select w from WhitelistedSite w"),
@NamedQuery(name = "WhitelistedSite.getByClientId", query = "select w from WhitelistedSite w where w.clientId = :clientId"),
@NamedQuery(name = "WhitelistedSite.getByCreatoruserId", query = "select w from WhitelistedSite w where w.creatorUserId = :userId")
}) })
public class WhitelistedSite { public class WhitelistedSite {
// unique id // unique id
private Long id; private Long id;
// who added this site to the whitelist (should be an admin) // Reference to the admin user who created this entry
private String userInfo; private String creatorUserId;
// which OAuth2 client is this tied to // which OAuth2 client is this tied to
private ClientDetailsEntity clientDetails; private String clientId;
// what scopes be allowed by default // what scopes be allowed by default
// this should include all information for what data to access // this should include all information for what data to access
@ -82,40 +82,28 @@ public class WhitelistedSite {
} }
/** /**
* @return the userInfo * @return the clientId
*/ */
@Basic @Basic
public String getUserInfo() { public String getClientId() {
return userInfo; return clientId;
} }
/** /**
* @param userInfo the userInfo to set * @param clientId the clientId to set
*/ */
public void setUserInfo(String userInfo) { public void setClientId(String clientId) {
this.userInfo = userInfo; this.clientId = clientId;
}
/**
* @return the clientDetails
*/
@ManyToOne
@JoinColumn(name="clientdetails_id")
public ClientDetailsEntity getClientDetails() {
return clientDetails;
}
/**
* @param clientDetails the clientDetails to set
*/
public void setClientDetails(ClientDetailsEntity clientDetails) {
this.clientDetails = clientDetails;
} }
/** /**
* @return the allowedScopes * @return the allowedScopes
*/ */
@ElementCollection(fetch = FetchType.EAGER) @ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(
name="allowed_scopes",
joinColumns=@JoinColumn(name="owner_id")
)
public Set<String> getAllowedScopes() { public Set<String> getAllowedScopes() {
return allowedScopes; return allowedScopes;
} }
@ -126,4 +114,13 @@ public class WhitelistedSite {
public void setAllowedScopes(Set<String> allowedScopes) { public void setAllowedScopes(Set<String> allowedScopes) {
this.allowedScopes = allowedScopes; this.allowedScopes = allowedScopes;
} }
@Basic
public String getCreatorUserId() {
return creatorUserId;
}
public void setCreatorUserId(String creatorUserId) {
this.creatorUserId = creatorUserId;
}
} }

View File

@ -17,14 +17,12 @@ package org.mitre.openid.connect.repository;
import java.util.Collection; import java.util.Collection;
import org.mitre.oauth2.model.ClientDetailsEntity;
import org.mitre.openid.connect.model.ApprovedSite; import org.mitre.openid.connect.model.ApprovedSite;
import org.mitre.openid.connect.model.UserInfo;
/** /**
* ApprovedSite repository interface * ApprovedSite repository interface
* *
* @author Michael Joseph Walsh * @author Michael Joseph Walsh, aanganes
* *
*/ */
public interface ApprovedSiteRepository { public interface ApprovedSiteRepository {
@ -47,22 +45,13 @@ public interface ApprovedSiteRepository {
/** /**
* Return a collection of ApprovedSite managed by this repository matching the * Return a collection of ApprovedSite managed by this repository matching the
* provided ClientDetailsEntity * provided client ID and user ID
* *
* @param clientId
* @param userId * @param userId
* @return * @return
*/ */
public Collection<ApprovedSite> getByClientDetails( public ApprovedSite getByClientIdAndUserId(String clientId, String userId);
ClientDetailsEntity clientDetails);
/**
* Return a collection of ApprovedSite managed by this repository matching the
* provided UserInfo
*
* @param userId
* @return
*/
public Collection<ApprovedSite> getByUserInfo(UserInfo userInfo);
/** /**
* Removes the given ApprovedSite from the repository * Removes the given ApprovedSite from the repository

View File

@ -22,7 +22,7 @@ import org.mitre.openid.connect.model.WhitelistedSite;
/** /**
* WhitelistedSite repository interface * WhitelistedSite repository interface
* *
* @author Michael Joseph Walsh * @author Michael Joseph Walsh, aanganes
* *
*/ */
public interface WhitelistedSiteRepository { public interface WhitelistedSiteRepository {
@ -43,6 +43,22 @@ public interface WhitelistedSiteRepository {
*/ */
public WhitelistedSite getById(Long id); public WhitelistedSite getById(Long id);
/**
* Find a WhitelistedSite by its associated ClientDetails reference
*
* @param client the Relying Party
* @return the corresponding WhitelistedSite if one exists for the RP, or null
*/
public WhitelistedSite getByClientId(String clientId);
/**
* Return a collection of the WhitelistedSites created by a given user
*
* @param creator the id of the admin who may have created some WhitelistedSites
* @return the collection of corresponding WhitelistedSites, if any, or null
*/
public Collection<WhitelistedSite> getByCreator(String creatorId);
/** /**
* Removes the given IdToken from the repository * Removes the given IdToken from the repository
* *

View File

@ -16,20 +16,23 @@
package org.mitre.openid.connect.service; package org.mitre.openid.connect.service;
import java.util.Collection; import java.util.Collection;
import java.util.Date;
import java.util.Set;
import org.mitre.oauth2.model.ClientDetailsEntity;
import org.mitre.openid.connect.model.ApprovedSite; import org.mitre.openid.connect.model.ApprovedSite;
import org.mitre.openid.connect.model.UserInfo; import org.mitre.openid.connect.model.WhitelistedSite;
/** /**
* Interface for ApprovedSite service * Interface for ApprovedSite service
* *
* @author Michael Joseph Walsh * @author Michael Joseph Walsh, aanganes
* *
*/ */
public interface ApprovedSiteService { public interface ApprovedSiteService {
public ApprovedSite createApprovedSite(String clientId, String userId, Date timeoutDate, Set<String> allowedScopes, WhitelistedSite whitelistedSite);
/** /**
* Return a collection of all ApprovedSites * Return a collection of all ApprovedSites
* *
@ -39,21 +42,13 @@ public interface ApprovedSiteService {
/** /**
* Return a collection of ApprovedSite managed by this repository matching the * Return a collection of ApprovedSite managed by this repository matching the
* provided ClientDetailsEntity * provided client ID and user ID
* *
* @param clientId
* @param userId * @param userId
* @return * @return
*/ */
public Collection<ApprovedSite> getByClientDetails(ClientDetailsEntity clientDetails); public ApprovedSite getByClientIdAndUserId(String clientId, String userId);
/**
* Return a collection of ApprovedSite managed by this repository matching the
* provided UserInfo
*
* @param userId
* @return
*/
public Collection<ApprovedSite> getByUserInfo(UserInfo userInfo);
/** /**
* Save an ApprovedSite * Save an ApprovedSite
@ -61,7 +56,7 @@ public interface ApprovedSiteService {
* @param approvedSite * @param approvedSite
* the ApprovedSite to be saved * the ApprovedSite to be saved
*/ */
public void save(ApprovedSite approvedSite); public ApprovedSite save(ApprovedSite approvedSite);
/** /**
* Get ApprovedSite for id * Get ApprovedSite for id

View File

@ -15,7 +15,6 @@
******************************************************************************/ ******************************************************************************/
package org.mitre.openid.connect.service; package org.mitre.openid.connect.service;
import org.mitre.openid.connect.model.DefaultUserInfo;
import org.mitre.openid.connect.model.UserInfo; import org.mitre.openid.connect.model.UserInfo;
/** /**
@ -32,7 +31,7 @@ public interface UserInfoService {
* @param userInfo * @param userInfo
* the UserInfo to be saved * the UserInfo to be saved
*/ */
public void save(DefaultUserInfo userInfo); public void save(UserInfo userInfo);
/** /**
* Get UserInfo for user id * Get UserInfo for user id

View File

@ -15,16 +15,25 @@
******************************************************************************/ ******************************************************************************/
package org.mitre.openid.connect.service; package org.mitre.openid.connect.service;
import java.util.Collection;
import org.mitre.openid.connect.model.WhitelistedSite; import org.mitre.openid.connect.model.WhitelistedSite;
/** /**
* Interface for WhitelistedSite service * Interface for WhitelistedSite service
* *
* @author Michael Joseph Walsh * @author Michael Joseph Walsh, aanganes
* *
*/ */
public interface WhitelistedSiteService { public interface WhitelistedSiteService {
/**
* Return a collection of all WhitelistedSite managed by this service
*
* @return the WhitelistedSite collection, or null
*/
public Collection<WhitelistedSite> getAll();
/** /**
* Returns the WhitelistedSite for the given id * Returns the WhitelistedSite for the given id
* *
@ -34,6 +43,22 @@ public interface WhitelistedSiteService {
*/ */
public WhitelistedSite getById(Long id); public WhitelistedSite getById(Long id);
/**
* Find a WhitelistedSite by its associated ClientDetails reference
*
* @param client the Relying Party
* @return the corresponding WhitelistedSite if one exists for the RP, or null
*/
public WhitelistedSite getByClientId(String clientId);
/**
* Return a collection of the WhitelistedSites created by a given user
*
* @param creator the user id of an admin who may have made some WhitelistedSites
* @return the collection of corresponding WhitelistedSites, if any, or null
*/
public Collection<WhitelistedSite> getByCreator(String creatorId);
/** /**
* Removes the given WhitelistedSite from the repository * Removes the given WhitelistedSite from the repository
* *

View File

@ -0,0 +1,4 @@
create table allowed_scopes(
owner_id VARCHAR(256),
allowedScopes VARCHAR(256)
);

View File

@ -1,8 +1,9 @@
CREATE TABLE approvedsite ( CREATE TABLE approvedsite (
id BIGINT AUTO_INCREMENT PRIMARY KEY, id BIGINT AUTO_INCREMENT PRIMARY KEY,
userinfo_id VARCHAR(256), userId VARCHAR(256),
clientdetails_id VARCHAR(256), clientId VARCHAR(256),
creationDate DATE, creationDate DATE,
accessDate DATE, accessDate DATE,
timeoutDate DATE timeoutDate DATE,
whitelistedsite_id VARCHAR(256)
); );

View File

@ -1,5 +1,5 @@
CREATE TABLE whitelistedsite ( CREATE TABLE whitelistedsite (
id BIGINT AUTO_INCREMENT PRIMARY KEY, id BIGINT AUTO_INCREMENT PRIMARY KEY,
userinfo_id VARCHAR(256), creatorUserId VARCHAR(256),
clientdetails_id VARCHAR(256) clientId VARCHAR(256)
); );

View File

@ -42,8 +42,6 @@ import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import com.google.common.collect.Sets;
/** /**
* @author jricher * @author jricher
@ -82,22 +80,7 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi
token.setClient(client); token.setClient(client);
// inherit the scope from the auth // inherit the scope from the auth
// this lets us match which scope is requested token.setScope(clientAuth.getScope());
if (client.isScoped()) {
// restrict granted scopes to a valid subset of those
Set<String> validScopes = Sets.newHashSet();
for (String requested : clientAuth.getScope()) {
if (client.getScope().contains(requested)) {
validScopes.add(requested);
} else {
logger.warn("Client " + client.getClientId() + " requested out of permission scope: " + requested);
}
}
token.setScope(validScopes);
}
// make it expire if necessary // make it expire if necessary
// TODO: pending upstream updates, check for 0 or -1 value here // TODO: pending upstream updates, check for 0 or -1 value here

View File

@ -18,23 +18,21 @@ package org.mitre.openid.connect.repository.impl;
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate; import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext; import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery; import javax.persistence.TypedQuery;
import org.mitre.oauth2.model.ClientDetailsEntity;
import org.mitre.openid.connect.model.ApprovedSite; import org.mitre.openid.connect.model.ApprovedSite;
import org.mitre.openid.connect.model.UserInfo;
import org.mitre.openid.connect.repository.ApprovedSiteRepository; import org.mitre.openid.connect.repository.ApprovedSiteRepository;
import org.mitre.util.jpa.JpaUtil;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
/** /**
* JPA ApprovedSite repository implementation * JPA ApprovedSite repository implementation
* *
* @author Michael Joseph Walsh * @author Michael Joseph Walsh, aanganes
* *
*/ */
@Repository @Repository
@ -51,38 +49,12 @@ public class JpaApprovedSiteRepository implements ApprovedSiteRepository {
return query.getResultList(); return query.getResultList();
} }
@Override
@Transactional
public Collection<ApprovedSite> getByClientDetails(
ClientDetailsEntity clientDetails) {
TypedQuery<ApprovedSite> query = manager.createNamedQuery(
"ApprovedSite.getByClientDetails", ApprovedSite.class);
query.setParameter("approvedSiteClientDetails", clientDetails);
List<ApprovedSite> found = query.getResultList();
return found;
}
@Override @Override
@Transactional @Transactional
public ApprovedSite getById(Long id) { public ApprovedSite getById(Long id) {
return manager.find(ApprovedSite.class, id); return manager.find(ApprovedSite.class, id);
} }
@Override
@Transactional
public Collection<ApprovedSite> getByUserInfo(UserInfo userInfo) {
TypedQuery<ApprovedSite> query = manager.createNamedQuery(
"ApprovedSite.getByUserInfo", ApprovedSite.class);
query.setParameter("approvedSiteUserInfo", userInfo.getUserId());
List<ApprovedSite> found = query.getResultList();
return found;
}
@Override @Override
@Transactional @Transactional
public void remove(ApprovedSite approvedSite) { public void remove(ApprovedSite approvedSite) {
@ -109,4 +81,14 @@ public class JpaApprovedSiteRepository implements ApprovedSiteRepository {
public ApprovedSite save(ApprovedSite approvedSite) { public ApprovedSite save(ApprovedSite approvedSite) {
return saveOrUpdate(approvedSite.getId(), manager, approvedSite); return saveOrUpdate(approvedSite.getId(), manager, approvedSite);
} }
@Override
public ApprovedSite getByClientIdAndUserId(String clientId, String userId) {
TypedQuery<ApprovedSite> query = manager.createNamedQuery("ApprovedSite.getByClientIdAndUserId", ApprovedSite.class);
query.setParameter("userId", userId);
query.setParameter("clientId", clientId);
return JpaUtil.getSingleResult(query.getResultList());
}
} }

View File

@ -25,13 +25,14 @@ import javax.persistence.TypedQuery;
import org.mitre.openid.connect.model.WhitelistedSite; import org.mitre.openid.connect.model.WhitelistedSite;
import org.mitre.openid.connect.repository.WhitelistedSiteRepository; import org.mitre.openid.connect.repository.WhitelistedSiteRepository;
import org.mitre.util.jpa.JpaUtil;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
/** /**
* JPA WhitelistedSite repository implementation * JPA WhitelistedSite repository implementation
* *
* @author Michael Joseph Walsh * @author Michael Joseph Walsh, aanganes
* *
*/ */
@Repository @Repository
@ -80,4 +81,21 @@ public class JpaWhitelistedSiteRepository implements WhitelistedSiteRepository {
public WhitelistedSite save(WhitelistedSite whiteListedSite) { public WhitelistedSite save(WhitelistedSite whiteListedSite) {
return saveOrUpdate(whiteListedSite.getId(), manager, whiteListedSite); return saveOrUpdate(whiteListedSite.getId(), manager, whiteListedSite);
} }
@Override
@Transactional
public WhitelistedSite getByClientId(String clientId) {
TypedQuery<WhitelistedSite> query = manager.createNamedQuery("WhitelistedSite.getByClientId", WhitelistedSite.class);
query.setParameter("clientId", clientId);
return JpaUtil.getSingleResult(query.getResultList());
}
@Override
@Transactional
public Collection<WhitelistedSite> getByCreator(String creatorId) {
TypedQuery<WhitelistedSite> query = manager.createNamedQuery("WhitelistedSite.getByCreaterUserId", WhitelistedSite.class);
query.setParameter("userId", creatorId);
return query.getResultList();
}
} }

View File

@ -16,10 +16,11 @@
package org.mitre.openid.connect.service.impl; package org.mitre.openid.connect.service.impl;
import java.util.Collection; import java.util.Collection;
import java.util.Date;
import java.util.Set;
import org.mitre.oauth2.model.ClientDetailsEntity;
import org.mitre.openid.connect.model.ApprovedSite; import org.mitre.openid.connect.model.ApprovedSite;
import org.mitre.openid.connect.model.UserInfo; import org.mitre.openid.connect.model.WhitelistedSite;
import org.mitre.openid.connect.repository.ApprovedSiteRepository; import org.mitre.openid.connect.repository.ApprovedSiteRepository;
import org.mitre.openid.connect.service.ApprovedSiteService; import org.mitre.openid.connect.service.ApprovedSiteService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -29,7 +30,7 @@ import org.springframework.transaction.annotation.Transactional;
/** /**
* Implementation of the ApprovedSiteService * Implementation of the ApprovedSiteService
* *
* @author Michael Joseph Walsh * @author Michael Joseph Walsh, aanganes
* *
*/ */
@Service @Service
@ -61,19 +62,8 @@ public class ApprovedSiteServiceImpl implements ApprovedSiteService {
} }
@Override @Override
public Collection<ApprovedSite> getByClientDetails( public ApprovedSite save(ApprovedSite approvedSite) {
ClientDetailsEntity clientDetails) { return approvedSiteRepository.save(approvedSite);
return approvedSiteRepository.getByClientDetails(clientDetails);
}
@Override
public Collection<ApprovedSite> getByUserInfo(UserInfo userInfo) {
return approvedSiteRepository.getByUserInfo(userInfo);
}
@Override
public void save(ApprovedSite approvedSite) {
approvedSiteRepository.save(approvedSite);
} }
@Override @Override
@ -91,4 +81,31 @@ public class ApprovedSiteServiceImpl implements ApprovedSiteService {
approvedSiteRepository.removeById(id); approvedSiteRepository.removeById(id);
} }
@Override
public ApprovedSite createApprovedSite(String clientId, String userId, Date timeoutDate, Set<String> allowedScopes,
WhitelistedSite whitelistedSite) {
ApprovedSite as = new ApprovedSite();
Date now = new Date();
as.setCreationDate(now);
as.setAccessDate(now);
as.setClientId(clientId);
as.setUserId(userId);
as.setTimeoutDate(timeoutDate);
as.setAllowedScopes(allowedScopes);
as.setWhitelistedSite(whitelistedSite);
return save(as);
}
@Override
public ApprovedSite getByClientIdAndUserId(String clientId,
String userId) {
return approvedSiteRepository.getByClientIdAndUserId(clientId, userId);
}
} }

View File

@ -15,7 +15,6 @@
******************************************************************************/ ******************************************************************************/
package org.mitre.openid.connect.service.impl; package org.mitre.openid.connect.service.impl;
import org.mitre.openid.connect.model.DefaultUserInfo;
import org.mitre.openid.connect.model.UserInfo; import org.mitre.openid.connect.model.UserInfo;
import org.mitre.openid.connect.repository.UserInfoRepository; import org.mitre.openid.connect.repository.UserInfoRepository;
import org.mitre.openid.connect.service.UserInfoService; import org.mitre.openid.connect.service.UserInfoService;
@ -53,7 +52,7 @@ public class UserInfoServiceImpl implements UserInfoService {
} }
@Override @Override
public void save(DefaultUserInfo userInfo) { public void save(UserInfo userInfo) {
userInfoRepository.save(userInfo); userInfoRepository.save(userInfo);
} }

View File

@ -15,6 +15,8 @@
******************************************************************************/ ******************************************************************************/
package org.mitre.openid.connect.service.impl; package org.mitre.openid.connect.service.impl;
import java.util.Collection;
import org.mitre.openid.connect.model.WhitelistedSite; import org.mitre.openid.connect.model.WhitelistedSite;
import org.mitre.openid.connect.repository.WhitelistedSiteRepository; import org.mitre.openid.connect.repository.WhitelistedSiteRepository;
import org.mitre.openid.connect.service.WhitelistedSiteService; import org.mitre.openid.connect.service.WhitelistedSiteService;
@ -25,7 +27,7 @@ import org.springframework.transaction.annotation.Transactional;
/** /**
* Implementation of the WhitelistedSiteService * Implementation of the WhitelistedSiteService
* *
* @author Michael Joseph Walsh * @author Michael Joseph Walsh, aanganes
* *
*/ */
@Service @Service
@ -71,4 +73,19 @@ public class WhitelistedSiteServiceImpl implements WhitelistedSiteService {
return whitelistedSiteRepository.save(whitelistedSite); return whitelistedSiteRepository.save(whitelistedSite);
} }
@Override
public Collection<WhitelistedSite> getAll() {
return whitelistedSiteRepository.getAll();
}
@Override
public WhitelistedSite getByClientId(String clientId) {
return whitelistedSiteRepository.getByClientId(clientId);
}
@Override
public Collection<WhitelistedSite> getByCreator(String creatorId) {
return whitelistedSiteRepository.getByCreator(creatorId);
}
} }

View File

@ -1,35 +0,0 @@
/*******************************************************************************
* Copyright 2012 The MITRE Corporation
*
* 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.openid.connect.token;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.approval.UserApprovalHandler;
public class JdbcUserApprovalHandler implements UserApprovalHandler {
@Override
public boolean isApproved(AuthorizationRequest authorizationRequest,
Authentication userAuthentication) {
//Check database to see if the user identified by the userAuthentication has stored an approval decision
userAuthentication.getPrincipal();
return false;
}
}

View File

@ -0,0 +1,172 @@
/*******************************************************************************
* Copyright 2012 The MITRE Corporation
*
* 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.openid.connect.token;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import org.mitre.openid.connect.model.ApprovedSite;
import org.mitre.openid.connect.model.WhitelistedSite;
import org.mitre.openid.connect.service.ApprovedSiteService;
import org.mitre.openid.connect.service.WhitelistedSiteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.exceptions.InvalidScopeException;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.approval.UserApprovalHandler;
import com.google.common.base.Splitter;
import com.google.common.collect.Sets;
/**
* Custom User Approval Handler implementation which uses a concept of a whitelist,
* blacklist, and greylist.
*
* Blacklisted sites will be caught and handled before this
* point.
*
* Whitelisted sites will be automatically approved, and an ApprovedSite entry will
* be created for the site the first time a given user access it.
*
* All other sites fall into the greylist - the user will be presented with the user
* approval page upon their first visit
* @author aanganes
*
*/
public class TofuUserApprovalHandler implements UserApprovalHandler {
@Autowired
ApprovedSiteService approvedSiteService;
@Autowired
WhitelistedSiteService whitelistedSiteService;
@Autowired
ClientDetailsService clientDetailsService;
/**
* Check if the user has already stored a positive approval decision for this site; or if the
* site is whitelisted, approve it automatically.
*
* Otherwise, return false so that the user will see the approval page and can make their own decision.
*
* @param authorizationRequest the incoming authorization request
* @param userAuthentication the Principal representing the currently-logged-in user
*
* @return true if the site is approved, false otherwise
*/
@Override
public boolean isApproved(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {
//First, check database to see if the user identified by the userAuthentication has stored an approval decision
//getName may not be filled in? TODO: investigate
String userId = userAuthentication.getName();
String clientId = authorizationRequest.getClientId();
ClientDetails client = clientDetailsService.loadClientByClientId(clientId);
String scopes = authorizationRequest.getAuthorizationParameters().get("scope");
Set<String> authRequestScopes = Sets.newHashSet(Splitter.on(" ").split(scopes));
//lookup ApprovedSites by userId and clientId
ApprovedSite ap = approvedSiteService.getByClientIdAndUserId(clientId, userId);
if (ap != null) {
if (scopesMatch(authRequestScopes, ap.getAllowedScopes())) {
//We have a match; update the access date on the AP entry and return true.
ap.setAccessDate(new Date());
approvedSiteService.save(ap);
return true;
}
}
WhitelistedSite ws = whitelistedSiteService.getByClientId(clientId);
if (ws != null && scopesMatch(authRequestScopes, ws.getAllowedScopes())) {
//Create an approved site
approvedSiteService.createApprovedSite(clientId, userId, null, ws.getAllowedScopes(), ws);
return true;
}
boolean approved = Boolean.parseBoolean(authorizationRequest.getApprovalParameters().get("user_oauth_approval"));
if (approved && !authorizationRequest.getApprovalParameters().isEmpty()) {
//Only store an ApprovedSite if the user has checked "remember this decision":
if (authorizationRequest.getApprovalParameters().get("remember") != null) {
//TODO: Remember may eventually have an option to remember for a specific amount
//of time; this would set the ApprovedSite.timeout.
Set<String> allowedScopes = Sets.newHashSet();
Map<String,String> approvalParams = authorizationRequest.getApprovalParameters();
Set<String> keys = approvalParams.keySet();
for (String key : keys) {
if (key.contains("scope")) {
//This is a scope parameter from the approval page. The value sent back should
//be the scope string. Check to make sure it is contained in the client's
//registered allowed scopes.
String scope = approvalParams.get(key);
//Make sure this scope is allowed for the given client
if (client.getScope().contains(scope)) {
allowedScopes.add(scope);
}
}
}
//FIXME: inject the final allowedScopes set into the AuthorizationRequest. The requester may have
//asked for many scopes and the user may have denied some of them.
approvedSiteService.createApprovedSite(clientId, userId, null, allowedScopes, null);
}
return true;
}
return false;
}
/**
* Check whether the requested scope set is a proper subset of the allowed scopes.
*
* @param requestedScopes
* @param allowedScopes
* @return
*/
private boolean scopesMatch(Set<String> requestedScopes, Set<String> allowedScopes) {
for (String scope : requestedScopes) {
if (!allowedScopes.contains(scope)) {
throw new InvalidScopeException("Invalid scope: " + scope, allowedScopes);
}
}
return true;
}
}

View File

@ -18,8 +18,6 @@ package org.mitre.openid.connect.web;
import java.security.Principal; import java.security.Principal;
import java.util.Set; import java.util.Set;
import org.mitre.oauth2.model.ClientDetailsEntity;
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
import org.mitre.oauth2.service.OAuth2TokenEntityService; import org.mitre.oauth2.service.OAuth2TokenEntityService;
import org.mitre.openid.connect.exception.UnknownUserInfoSchemaException; import org.mitre.openid.connect.exception.UnknownUserInfoSchemaException;
import org.mitre.openid.connect.model.DefaultUserInfo; import org.mitre.openid.connect.model.DefaultUserInfo;

View File

@ -14,6 +14,7 @@
<class>org.mitre.openid.connect.model.IdToken</class> <class>org.mitre.openid.connect.model.IdToken</class>
<class>org.mitre.openid.connect.model.IdTokenClaims</class> <class>org.mitre.openid.connect.model.IdTokenClaims</class>
<class>org.mitre.openid.connect.model.DefaultUserInfo</class> <class>org.mitre.openid.connect.model.DefaultUserInfo</class>
<!-- <class>org.mitre.openid.connect.model.UserInfo</class> -->
<class>org.mitre.openid.connect.model.WhitelistedSite</class> <class>org.mitre.openid.connect.model.WhitelistedSite</class>
<shared-cache-mode>NONE</shared-cache-mode> <shared-cache-mode>NONE</shared-cache-mode>
</persistence-unit> </persistence-unit>

View File

@ -55,7 +55,7 @@
client-details-service-ref="defaultOAuth2ClientDetailsEntityService" client-details-service-ref="defaultOAuth2ClientDetailsEntityService"
authorization-request-factory-ref="authorizationRequestFactory" authorization-request-factory-ref="authorizationRequestFactory"
token-services-ref="defaultOAuth2ProviderTokenService" token-services-ref="defaultOAuth2ProviderTokenService"
user-approval-handler-ref="userApprovalHandler" user-approval-handler-ref="jdbcUserApprovalHandler"
authorization-endpoint-url="/authorize" authorization-endpoint-url="/authorize"
token-endpoint-url="/token"> token-endpoint-url="/token">
@ -80,8 +80,7 @@
</constructor-arg> </constructor-arg>
</bean> </bean>
<bean class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler" id="userApprovalHandler"> <bean class="org.mitre.openid.connect.token.TofuUserApprovalHandler" id="jdbcUserApprovalHandler">
<property name="tokenServices" ref="defaultOAuth2ProviderTokenService" />
</bean> </bean>
<bean id="authCodeServices" class="org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices" /> <bean id="authCodeServices" class="org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices" />

View File

@ -62,16 +62,20 @@
<div class="span4"> <div class="span4">
<fieldset style="text-align:left" class="well"> <fieldset style="text-align:left" class="well">
<legend style="margin-bottom: 0;">Access to:</legend> <legend style="margin-bottom: 0;">Access to:</legend>
<label for="option1"></label>
<input type="checkbox" name="option1" id="option1" checked="checked"> basic profile information <input type="hidden" name="scope_openid" id="scope_openid" value="openid"/>
<label for="option2"></label> <input type="checkbox" name="scope_profile" id="scope_profile" value="profile" checked="checked"><label for="scope_profile">basic profile information</label>
<input type="checkbox" name="option1" id="option2" checked="checked"> email address
<label for="option3"></label> <input type="checkbox" name="scope_email" id="scope_email" value="email" checked="checked"><label for="scope_email">email address</label>
<input type="checkbox" name="option3" id="option3" checked="checked"> address
<label for="option4"></label> <input type="checkbox" name="scope_address" id="scope_address" value="address" checked="checked"><label for="scope_address">address</label>
<input type="checkbox" name="option4" id="option4" checked="checked"> phone number
<label for="option5"></label> <input type="checkbox" name="scope_phone" id="scope_phone" value="phone" checked="checked"><label for="scope_phone">phone number</label>
<input type="checkbox" name="option5" id="option5" checked="checked"> offline access
<input type="checkbox" name="scope_offline" id="scope_offline" value="offline" checked="checked"><label for="scope_offline">offline access</label>
<input type="checkbox" name="remember" id="remember" value="true" checked="checked"><label for="remember">remember this decision</label>
</fieldset> </fieldset>
</div> </div>