Fixed error logging; added ApprovedSite tracking to tokens

pull/340/head
Amanda Anganes 2013-04-22 15:49:06 -04:00
parent 82fca45412
commit a79aca906e
14 changed files with 273 additions and 36 deletions

View File

@ -43,13 +43,12 @@ import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.Transient;
import org.mitre.openid.connect.model.ApprovedSite;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.JWTParser;
import com.nimbusds.jwt.PlainJWT;
/**
* @author jricher
@ -92,6 +91,8 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
private Set<String> scope;
private ApprovedSite approvedSite; //Back-reference for one-to-many relationship
/**
* Create a new, blank access token
*/
@ -284,4 +285,20 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
// TODO Auto-generated method stub
return 0;
}
/**
* @return the approvedSite
*/
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="approved_site_id", referencedColumnName="id")
public ApprovedSite getApprovedSite() {
return approvedSite;
}
/**
* @param approvedSite the approvedSite to set
*/
public void setApprovedSite(ApprovedSite approvedSite) {
this.approvedSite = approvedSite;
}
}

View File

@ -15,10 +15,12 @@
******************************************************************************/
package org.mitre.openid.connect.model;
import java.io.Serializable;
import java.util.Date;
import java.util.Set;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
@ -31,10 +33,15 @@ import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.Transient;
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
import com.google.common.collect.Sets;
@Entity
@Table(name="approved_site")
@NamedQueries({
@ -43,9 +50,11 @@ import javax.persistence.Transient;
@NamedQuery(name = "ApprovedSite.getByClientId", query = "select a from ApprovedSite a where a.clientId = :clientId"),
@NamedQuery(name = "ApprovedSite.getByClientIdAndUserId", query = "select a from ApprovedSite a where a.clientId = :clientId and a.userId = :userId")
})
public class ApprovedSite {
public class ApprovedSite implements Serializable {
// unique id
private static final long serialVersionUID = 1L;
// unique id
private Long id;
// which user made the approval
@ -70,7 +79,8 @@ public class ApprovedSite {
// If this AP is a WS, link to the WS
private WhitelistedSite whitelistedSite;
// TODO: should we store the OAuth2 tokens and IdTokens here?
//Link to any access tokens approved through this stored decision
private Set<OAuth2AccessTokenEntity> approvedAccessTokens = Sets.newHashSet();
/**
* Empty constructor
@ -235,5 +245,123 @@ public class ApprovedSite {
return false;
}
}
/**
* @return the approvedAccessTokens
*/
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="approvedSite")
public Set<OAuth2AccessTokenEntity> getApprovedAccessTokens() {
return approvedAccessTokens;
}
/**
* @param approvedAccessTokens the approvedAccessTokens to set
*/
public void setApprovedAccessTokens(Set<OAuth2AccessTokenEntity> approvedAccessTokens) {
this.approvedAccessTokens = approvedAccessTokens;
}
public void addApprovedAccessToken(OAuth2AccessTokenEntity token) {
this.getApprovedAccessTokens();
this.approvedAccessTokens.add(token);
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((accessDate == null) ? 0 : accessDate.hashCode());
result = prime * result
+ ((allowedScopes == null) ? 0 : allowedScopes.hashCode());
result = prime * result
+ ((clientId == null) ? 0 : clientId.hashCode());
result = prime * result
+ ((creationDate == null) ? 0 : creationDate.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result
+ ((timeoutDate == null) ? 0 : timeoutDate.hashCode());
result = prime * result + ((userId == null) ? 0 : userId.hashCode());
result = prime * result
+ ((whitelistedSite == null) ? 0 : whitelistedSite.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 (!(obj instanceof ApprovedSite)) {
return false;
}
ApprovedSite other = (ApprovedSite) obj;
if (accessDate == null) {
if (other.accessDate != null) {
return false;
}
} else if (!accessDate.equals(other.accessDate)) {
return false;
}
if (allowedScopes == null) {
if (other.allowedScopes != null) {
return false;
}
} else if (!allowedScopes.equals(other.allowedScopes)) {
return false;
}
if (clientId == null) {
if (other.clientId != null) {
return false;
}
} else if (!clientId.equals(other.clientId)) {
return false;
}
if (creationDate == null) {
if (other.creationDate != null) {
return false;
}
} else if (!creationDate.equals(other.creationDate)) {
return false;
}
if (id == null) {
if (other.id != null) {
return false;
}
} else if (!id.equals(other.id)) {
return false;
}
if (timeoutDate == null) {
if (other.timeoutDate != null) {
return false;
}
} else if (!timeoutDate.equals(other.timeoutDate)) {
return false;
}
if (userId == null) {
if (other.userId != null) {
return false;
}
} else if (!userId.equals(other.userId)) {
return false;
}
if (whitelistedSite == null) {
if (other.whitelistedSite != null) {
return false;
}
} else if (!whitelistedSite.equals(other.whitelistedSite)) {
return false;
}
return true;
}
}

View File

@ -15,6 +15,7 @@
******************************************************************************/
package org.mitre.openid.connect.model;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.Basic;
@ -44,9 +45,11 @@ import javax.persistence.Table;
@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 implements Serializable {
// unique id
private static final long serialVersionUID = 1L;
// unique id
private Long id;
// Reference to the admin user who created this entry
@ -127,4 +130,67 @@ public class WhitelistedSite {
public void setCreatorUserId(String creatorUserId) {
this.creatorUserId = creatorUserId;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((allowedScopes == null) ? 0 : allowedScopes.hashCode());
result = prime * result
+ ((clientId == null) ? 0 : clientId.hashCode());
result = prime * result
+ ((creatorUserId == null) ? 0 : creatorUserId.hashCode());
result = prime * result + ((id == null) ? 0 : id.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 (!(obj instanceof WhitelistedSite)) {
return false;
}
WhitelistedSite other = (WhitelistedSite) obj;
if (allowedScopes == null) {
if (other.allowedScopes != null) {
return false;
}
} else if (!allowedScopes.equals(other.allowedScopes)) {
return false;
}
if (clientId == null) {
if (other.clientId != null) {
return false;
}
} else if (!clientId.equals(other.clientId)) {
return false;
}
if (creatorUserId == null) {
if (other.creatorUserId != null) {
return false;
}
} else if (!creatorUserId.equals(other.creatorUserId)) {
return false;
}
if (id == null) {
if (other.id != null) {
return false;
}
} else if (!id.equals(other.id)) {
return false;
}
return true;
}
}

View File

@ -18,16 +18,12 @@
*/
package org.mitre.oauth2.service.impl;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.joda.time.DateTime;
import org.joda.time.Period;
import org.mitre.oauth2.exception.NonceReuseException;
import org.mitre.oauth2.model.AuthenticationHolderEntity;
import org.mitre.oauth2.model.ClientDetailsEntity;
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
@ -36,8 +32,6 @@ import org.mitre.oauth2.repository.AuthenticationHolderRepository;
import org.mitre.oauth2.repository.OAuth2TokenRepository;
import org.mitre.oauth2.service.ClientDetailsEntityService;
import org.mitre.oauth2.service.OAuth2TokenEntityService;
import org.mitre.openid.connect.model.Nonce;
import org.mitre.openid.connect.service.NonceService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

View File

@ -64,7 +64,7 @@ public class IntrospectionEndpoint {
Map<String, Object> model = new HashMap<String, Object>();
model.put("entity", e);
logger.error("InvalidTokenException: " + ex.getStackTrace().toString());
logger.error("InvalidTokenException: ", ex);
model.put("code", HttpStatus.BAD_REQUEST);
@ -106,7 +106,7 @@ public class IntrospectionEndpoint {
try {
token = tokenServices.readAccessToken(tokenValue);
} catch (AuthenticationException e) {
logger.error("Verify failed; AuthenticationException: " + e.getStackTrace().toString());
logger.error("Verify failed; AuthenticationException: ", e);
modelAndView.addObject("code", HttpStatus.FORBIDDEN);
modelAndView.setViewName("httpCodeView");
return modelAndView;

View File

@ -77,12 +77,12 @@ public class OAuthConfirmationController {
client = clientService.loadClientByClientId(clientAuth.getClientId());
} catch (OAuth2Exception e) {
logger.error("confirmAccess: OAuth2Exception was thrown when attempting to load client: "
+ e.getStackTrace().toString());
, e);
model.put("code", HttpStatus.BAD_REQUEST);
return new ModelAndView("httpCodeView");
} catch (IllegalArgumentException e) {
logger.error("confirmAccess: IllegalArgumentException was thrown when attempting to load client: "
+ e.getStackTrace().toString());
, e);
model.put("code", HttpStatus.BAD_REQUEST);
return new ModelAndView("httpCodeView");
}

View File

@ -24,10 +24,12 @@ import org.mitre.oauth2.model.ClientDetailsEntity;
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
import org.mitre.oauth2.service.ClientDetailsEntityService;
import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
import org.mitre.openid.connect.model.ApprovedSite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.stereotype.Service;
@ -57,8 +59,16 @@ public class ConnectTokenEnhancer implements TokenEnhancer {
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
OAuth2AccessTokenEntity token = (OAuth2AccessTokenEntity) accessToken;
AuthorizationRequest originalAuthRequest = authentication.getAuthorizationRequest();
String clientId = authentication.getAuthorizationRequest().getClientId();
if (originalAuthRequest.getExtensionProperties().containsKey("approved_site")) {
//Add the token to the approved site reference, if there is one
ApprovedSite ap = (ApprovedSite)originalAuthRequest.getExtensionProperties().get("approved_site");
//ap.addApprovedAccessToken(token);
token.setApprovedSite(ap);
}
String clientId = originalAuthRequest.getClientId();
ClientDetailsEntity client = clientService.loadClientByClientId(clientId);
JWTClaimsSet claims = new JWTClaimsSet();
@ -87,7 +97,7 @@ public class ConnectTokenEnhancer implements TokenEnhancer {
* has the proper scope, we can consider this a valid OpenID Connect request. Otherwise,
* we consider it to be a vanilla OAuth2 request.
*/
if (authentication.getAuthorizationRequest().getScope().contains("openid")) {
if (originalAuthRequest.getScope().contains("openid")) {
// TODO: maybe id tokens need a service layer
@ -114,7 +124,7 @@ public class ConnectTokenEnhancer implements TokenEnhancer {
idClaims.setAudience(Lists.newArrayList(clientId));
String nonce = authentication.getAuthorizationRequest().getAuthorizationParameters().get("nonce");
String nonce = originalAuthRequest.getAuthorizationParameters().get("nonce");
if (!Strings.isNullOrEmpty(nonce)) {
idClaims.setCustomClaim("nonce", nonce);
}

View File

@ -117,6 +117,7 @@ public class TofuUserApprovalHandler implements UserApprovalHandler {
ap.setAccessDate(new Date());
approvedSiteService.save(ap);
authorizationRequest.getExtensionProperties().put("approved_site", ap);
authorizationRequest.setApproved(true);
alreadyApproved = true;
}
@ -128,7 +129,8 @@ public class TofuUserApprovalHandler implements UserApprovalHandler {
if (ws != null && scopesMatch(authorizationRequest.getScope(), ws.getAllowedScopes())) {
//Create an approved site
approvedSiteService.createApprovedSite(clientId, userId, null, ws.getAllowedScopes(), ws);
ApprovedSite newSite = approvedSiteService.createApprovedSite(clientId, userId, null, ws.getAllowedScopes(), ws);
authorizationRequest.getExtensionProperties().put("approved_site", newSite);
authorizationRequest.setApproved(true);
}
}
@ -189,7 +191,8 @@ public class TofuUserApprovalHandler implements UserApprovalHandler {
timeout = cal.getTime();
}
approvedSiteService.createApprovedSite(clientId, userId, timeout, allowedScopes, null);
ApprovedSite newSite = approvedSiteService.createApprovedSite(clientId, userId, timeout, allowedScopes, null);
authorizationRequest.getExtensionProperties().put("approved_site", newSite);
}
}

View File

@ -5,7 +5,10 @@ package org.mitre.openid.connect.web;
import java.security.Principal;
import java.util.Collection;
import java.util.Set;
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
import org.mitre.oauth2.service.OAuth2TokenEntityService;
import org.mitre.openid.connect.model.ApprovedSite;
import org.mitre.openid.connect.service.ApprovedSiteService;
import org.slf4j.Logger;
@ -31,6 +34,9 @@ public class ApprovedSiteAPI {
@Autowired
private ApprovedSiteService approvedSiteService;
@Autowired
OAuth2TokenEntityService tokenServices;
private static Logger logger = LoggerFactory.getLogger(ApprovedSiteAPI.class);
/**
@ -69,7 +75,19 @@ public class ApprovedSiteAPI {
return "jsonErrorView";
} else {
m.put("code", HttpStatus.OK);
Set<OAuth2AccessTokenEntity> accessTokens = approvedSite.getApprovedAccessTokens();
for (OAuth2AccessTokenEntity token : accessTokens) {
if (token.getRefreshToken() != null) {
//TODO: how should refresh tokens be handled if you delete an approved site?
//tokenServices.revokeRefreshToken(token.getRefreshToken());
}
tokenServices.revokeAccessToken(token);
}
approvedSiteService.remove(approvedSite);
}
return "httpCodeView";

View File

@ -80,12 +80,12 @@ public class BlacklistAPI {
}
catch (JsonSyntaxException e) {
logger.error("addNewBlacklistedSite failed due to JsonSyntaxException: " + e.getStackTrace().toString());
logger.error("addNewBlacklistedSite failed due to JsonSyntaxException: " , e);
m.put("code", HttpStatus.BAD_REQUEST);
m.put("errorMessage", "Could not save new blacklisted site. The server encountered a JSON syntax exception. Contact a system administrator for assistance.");
return "jsonErrorView";
} catch (IllegalStateException e) {
logger.error("addNewBlacklistedSite failed due to IllegalStateException: " + e.getStackTrace().toString());
logger.error("addNewBlacklistedSite failed due to IllegalStateException: " , e);
m.put("code", HttpStatus.BAD_REQUEST);
m.put("errorMessage", "Could not save new blacklisted site. The server encountered an IllegalStateException. Refresh and try again - if the problem persists, contact a system administrator for assistance.");
return "jsonErrorView";
@ -112,12 +112,12 @@ public class BlacklistAPI {
}
catch (JsonSyntaxException e) {
logger.error("updateBlacklistedSite failed due to JsonSyntaxException: " + e.getStackTrace().toString());
logger.error("updateBlacklistedSite failed due to JsonSyntaxException: " , e);
m.put("code", HttpStatus.BAD_REQUEST);
m.put("errorMessage", "Could not update blacklisted site. The server encountered a JSON syntax exception. Contact a system administrator for assistance.");
return "jsonErrorView";
} catch (IllegalStateException e) {
logger.error("updateBlacklistedSite failed due to IllegalStateException: " + e.getStackTrace().toString());
logger.error("updateBlacklistedSite failed due to IllegalStateException: " , e);
m.put("code", HttpStatus.BAD_REQUEST);
m.put("errorMessage", "Could not update blacklisted site. The server encountered an IllegalStateException. Refresh and try again - if the problem persists, contact a system administrator for assistance.");
return "jsonErrorView";

View File

@ -136,12 +136,12 @@ public class ClientAPI {
client = gson.fromJson(json, ClientDetailsEntity.class);
}
catch (JsonSyntaxException e) {
logger.error("apiAddClient failed due to JsonSyntaxException: " + e.getStackTrace().toString());
logger.error("apiAddClient failed due to JsonSyntaxException: " , e);
m.addAttribute("code", HttpStatus.BAD_REQUEST);
m.addAttribute("errorMessage", "Could not save new client. The server encountered a JSON syntax exception. Contact a system administrator for assistance.");
return "jsonErrorView";
} catch (IllegalStateException e) {
logger.error("apiAddClient failed due to IllegalStateException: " + e.getStackTrace().toString());
logger.error("apiAddClient failed due to IllegalStateException: " , e);
m.addAttribute("code", HttpStatus.BAD_REQUEST);
m.addAttribute("errorMessage", "Could not save new client. The server encountered an IllegalStateException. Refresh and try again - if the problem persists, contact a system administrator for assistance.");
return "jsonErrorView";
@ -193,12 +193,12 @@ public class ClientAPI {
client = gson.fromJson(json, ClientDetailsEntity.class);
}
catch (JsonSyntaxException e) {
logger.error("apiUpdateClient failed due to JsonSyntaxException: " + e.getStackTrace().toString());
logger.error("apiUpdateClient failed due to JsonSyntaxException: " , e);
m.addAttribute("code", HttpStatus.BAD_REQUEST);
m.addAttribute("errorMessage", "Could not update client. The server encountered a JSON syntax exception. Contact a system administrator for assistance.");
return "jsonErrorView";
} catch (IllegalStateException e) {
logger.error("apiUpdateClient failed due to IllegalStateException: " + e.getStackTrace().toString());
logger.error("apiUpdateClient failed due to IllegalStateException: " , e);
m.addAttribute("code", HttpStatus.BAD_REQUEST);
m.addAttribute("errorMessage", "Could not update client. The server encountered an IllegalStateException. Refresh and try again - if the problem persists, contact a system administrator for assistance.");
return "jsonErrorView";

View File

@ -76,12 +76,12 @@ public class WhitelistAPI {
whitelist = gson.fromJson(json, WhitelistedSite.class);
} catch (JsonParseException e) {
logger.error("addNewWhitelistedSite failed due to JsonParseException: " + e.getStackTrace().toString());
logger.error("addNewWhitelistedSite failed due to JsonParseException: " , e);
m.addAttribute("code", HttpStatus.BAD_REQUEST);
m.addAttribute("errorMessage", "Could not save new whitelisted site. The server encountered a JSON syntax exception. Contact a system administrator for assistance.");
return "jsonErrorView";
} catch (IllegalStateException e) {
logger.error("addNewWhitelistedSite failed due to IllegalStateException: " + e.getStackTrace().toString());
logger.error("addNewWhitelistedSite failed due to IllegalStateException: " , e);
m.addAttribute("code", HttpStatus.BAD_REQUEST);
m.addAttribute("errorMessage", "Could not save new whitelisted site. The server encountered an IllegalStateException. Refresh and try again - if the problem persists, contact a system administrator for assistance.");
return "jsonErrorView";
@ -113,12 +113,12 @@ public class WhitelistAPI {
whitelist = gson.fromJson(json, WhitelistedSite.class);
} catch (JsonParseException e) {
logger.error("updateWhitelistedSite failed due to JsonParseException: " + e.getStackTrace().toString());
logger.error("updateWhitelistedSite failed due to JsonParseException: " , e);
m.put("code", HttpStatus.BAD_REQUEST);
m.put("errorMessage", "Could not update whitelisted site. The server encountered a JSON syntax exception. Contact a system administrator for assistance.");
return "jsonErrorView";
} catch (IllegalStateException e) {
logger.error("updateWhitelistedSite failed due to IllegalStateException: " + e.getStackTrace().toString());
logger.error("updateWhitelistedSite failed due to IllegalStateException: " , e);
m.put("code", HttpStatus.BAD_REQUEST);
m.put("errorMessage", "Could not update whitelisted site. The server encountered an IllegalStateException. Refresh and try again - if the problem persists, contact a system administrator for assistance.");
return "jsonErrorView";

View File

@ -10,7 +10,8 @@ CREATE TABLE IF NOT EXISTS access_token (
refresh_token_id BIGINT,
client_id VARCHAR(256),
auth_holder_id BIGINT,
id_token_id BIGINT
id_token_id BIGINT,
approved_site_id BIGINT
);
CREATE TABLE IF NOT EXISTS address (

@ -1 +1 @@
Subproject commit 570f83ff8a9d27022cb0f2a17f72a26f019120bb
Subproject commit 24b8229e5cc34504d5854ec41e3c4b7248981dc2