Merge branch 'uma'
commit
bf2449b693
|
@ -36,14 +36,17 @@ import javax.persistence.GeneratedValue;
|
|||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import org.mitre.uma.model.Permission;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessTokenJackson1Deserializer;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessTokenJackson1Serializer;
|
||||
|
@ -109,6 +112,8 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
|
|||
private OAuth2RefreshTokenEntity refreshToken;
|
||||
|
||||
private Set<String> scope;
|
||||
|
||||
private Set<Permission> permissions;
|
||||
|
||||
/**
|
||||
* Create a new, blank access token
|
||||
|
@ -321,4 +326,24 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the permissions
|
||||
*/
|
||||
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
|
||||
@JoinTable(
|
||||
name = "access_token_permissions",
|
||||
joinColumns = @JoinColumn(name = "access_token_id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "permission_id")
|
||||
)
|
||||
public Set<Permission> getPermissions() {
|
||||
return permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param permissions the permissions to set
|
||||
*/
|
||||
public void setPermissions(Set<Permission> permissions) {
|
||||
this.permissions = permissions;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.mitre.oauth2.service;
|
|||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.text.DateFormatter;
|
||||
|
||||
|
@ -46,17 +47,19 @@ public interface IntrospectionResultAssembler {
|
|||
*
|
||||
* @param accessToken the access token
|
||||
* @param userInfo the user info
|
||||
* @param authScopes the scopes the client is authorized for
|
||||
* @return the token introspection result
|
||||
*/
|
||||
Map<String, Object> assembleFrom(OAuth2AccessTokenEntity accessToken, UserInfo userInfo);
|
||||
Map<String, Object> assembleFrom(OAuth2AccessTokenEntity accessToken, UserInfo userInfo, Set<String> authScopes);
|
||||
|
||||
/**
|
||||
* Assemble a token introspection result from the given refresh token and user info.
|
||||
*
|
||||
* @param refreshToken the refresh token
|
||||
* @param userInfo the user info
|
||||
* @param authScopes the scopes the client is authorized for
|
||||
* @return the token introspection result
|
||||
*/
|
||||
Map<String, Object> assembleFrom(OAuth2RefreshTokenEntity refreshToken, UserInfo userInfo);
|
||||
Map<String, Object> assembleFrom(OAuth2RefreshTokenEntity refreshToken, UserInfo userInfo, Set<String> authScopes);
|
||||
|
||||
}
|
||||
|
|
|
@ -33,9 +33,11 @@ public interface SystemScopeService {
|
|||
|
||||
public static final String OFFLINE_ACCESS = "offline_access";
|
||||
public static final String OPENID_SCOPE = "openid";
|
||||
public static final String ID_TOKEN_SCOPE = "id-token";
|
||||
public static final String REGISTRATION_TOKEN_SCOPE = "registration-token";
|
||||
public static final String RESOURCE_TOKEN_SCOPE = "resource-token";
|
||||
public static final String ID_TOKEN_SCOPE = "id-token"; // ID tokens are generated using this scope
|
||||
public static final String REGISTRATION_TOKEN_SCOPE = "registration-token"; // this scope manages dynamic client registrations
|
||||
public static final String RESOURCE_TOKEN_SCOPE = "resource-token"; // this scope manages client-style protected resources
|
||||
public static final String UMA_PROTECTION_SCOPE = "uma_protection";
|
||||
public static final String UMA_AUTHORIZATION_SCOPE = "uma_authorization";
|
||||
|
||||
public static final Set<SystemScope> reservedScopes =
|
||||
Sets.newHashSet(
|
||||
|
|
|
@ -49,6 +49,8 @@ public class ConfigurationPropertiesBean {
|
|||
private String logoImageUrl;
|
||||
|
||||
private Long regTokenLifeTime;
|
||||
|
||||
private Long rqpTokenLifeTime;
|
||||
|
||||
private boolean forceHttps = false; // by default we just log a warning for HTTPS deployment
|
||||
|
||||
|
@ -131,6 +133,20 @@ public class ConfigurationPropertiesBean {
|
|||
this.regTokenLifeTime = regTokenLifeTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the rqpTokenLifeTime
|
||||
*/
|
||||
public Long getRqpTokenLifeTime() {
|
||||
return rqpTokenLifeTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rqpTokenLifeTime the rqpTokenLifeTime to set
|
||||
*/
|
||||
public void setRqpTokenLifeTime(Long rqpTokenLifeTime) {
|
||||
this.rqpTokenLifeTime = rqpTokenLifeTime;
|
||||
}
|
||||
|
||||
public boolean isForceHttps() {
|
||||
return forceHttps;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.Set;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
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.Table;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "claim")
|
||||
public class Claim {
|
||||
|
||||
private Long id;
|
||||
private String name;
|
||||
private String friendlyName;
|
||||
private String claimType;
|
||||
private String value;
|
||||
private Set<String> claimTokenFormat;
|
||||
private Set<String> issuer;
|
||||
|
||||
/**
|
||||
* @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 name
|
||||
*/
|
||||
@Basic
|
||||
@Column(name = "name")
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
/**
|
||||
* @param name the name to set
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the friendlyName
|
||||
*/
|
||||
@Basic
|
||||
@Column(name = "friendly_name")
|
||||
public String getFriendlyName() {
|
||||
return friendlyName;
|
||||
}
|
||||
/**
|
||||
* @param friendlyName the friendlyName to set
|
||||
*/
|
||||
public void setFriendlyName(String friendlyName) {
|
||||
this.friendlyName = friendlyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the claimType
|
||||
*/
|
||||
@Basic
|
||||
@Column(name = "claim_type")
|
||||
public String getClaimType() {
|
||||
return claimType;
|
||||
}
|
||||
/**
|
||||
* @param claimType the claimType to set
|
||||
*/
|
||||
public void setClaimType(String claimType) {
|
||||
this.claimType = claimType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the claimTokenFormat
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@Column(name = "claim_token_format")
|
||||
@CollectionTable(
|
||||
name = "claim_token_format",
|
||||
joinColumns = @JoinColumn(name = "owner_id")
|
||||
)
|
||||
public Set<String> getClaimTokenFormat() {
|
||||
return claimTokenFormat;
|
||||
}
|
||||
/**
|
||||
* @param claimTokenFormat the claimTokenFormat to set
|
||||
*/
|
||||
public void setClaimTokenFormat(Set<String> claimTokenFormat) {
|
||||
this.claimTokenFormat = claimTokenFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the issuer
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@Column(name = "issuer")
|
||||
@CollectionTable(
|
||||
name = "claim_issuer",
|
||||
joinColumns = @JoinColumn(name = "owner_id")
|
||||
)
|
||||
public Set<String> getIssuer() {
|
||||
return issuer;
|
||||
}
|
||||
/**
|
||||
* @param issuer the issuer to set
|
||||
*/
|
||||
public void setIssuer(Set<String> issuer) {
|
||||
this.issuer = issuer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the value
|
||||
*/
|
||||
@Basic
|
||||
@Column(name = "claim_value")
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* @param value the value to set
|
||||
*/
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.Set;
|
||||
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
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.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "permission")
|
||||
public class Permission {
|
||||
|
||||
private Long id;
|
||||
private ResourceSet resourceSet;
|
||||
private Set<String> scopes;
|
||||
|
||||
/**
|
||||
* @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 resourceSet
|
||||
*/
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "resource_set_id")
|
||||
public ResourceSet getResourceSet() {
|
||||
return resourceSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resourceSet the resourceSet to set
|
||||
*/
|
||||
public void setResourceSet(ResourceSet resourceSet) {
|
||||
this.resourceSet = resourceSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the scopes
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@Column(name = "scope")
|
||||
@CollectionTable(
|
||||
name = "permission_scope",
|
||||
joinColumns = @JoinColumn(name = "owner_id")
|
||||
)
|
||||
public Set<String> getScopes() {
|
||||
return scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param scopes the scopes to set
|
||||
*/
|
||||
public void setScopes(Set<String> scopes) {
|
||||
this.scopes = scopes;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
/**
|
||||
*
|
||||
* An UMA permission, used in the protection API.
|
||||
*
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "permission_ticket")
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = PermissionTicket.QUERY_TICKET, query = "select p from PermissionTicket p where p.ticket = :" + PermissionTicket.PARAM_TICKET)
|
||||
})
|
||||
public class PermissionTicket {
|
||||
|
||||
public static final String QUERY_TICKET = "PermissionTicket.queryByTicket";
|
||||
public static final String PARAM_TICKET = "ticket";
|
||||
|
||||
private Long id;
|
||||
private Permission permission;
|
||||
private String ticket;
|
||||
private Date expiration;
|
||||
private Collection<Claim> claimsSupplied;
|
||||
|
||||
/**
|
||||
* @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 permission
|
||||
*/
|
||||
@OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
|
||||
@JoinColumn(name = "permission_id")
|
||||
public Permission getPermission() {
|
||||
return permission;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param permission the permission to set
|
||||
*/
|
||||
public void setPermission(Permission permission) {
|
||||
this.permission = permission;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the ticket
|
||||
*/
|
||||
@Basic
|
||||
@Column(name = "ticket")
|
||||
public String getTicket() {
|
||||
return ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ticket the ticket to set
|
||||
*/
|
||||
public void setTicket(String ticket) {
|
||||
this.ticket = ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
@JoinColumn(name = "permission_ticket_id")
|
||||
public Collection<Claim> getClaimsSupplied() {
|
||||
return claimsSupplied;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param claimsSupplied the claimsSupplied to set
|
||||
*/
|
||||
public void setClaimsSupplied(Collection<Claim> claimsSupplied) {
|
||||
this.claimsSupplied = claimsSupplied;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,217 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.Set;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
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.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "resource_set")
|
||||
@NamedQueries ({
|
||||
@NamedQuery(name = ResourceSet.QUERY_BY_OWNER, query = "select r from ResourceSet r where r.owner = :" + ResourceSet.PARAM_OWNER),
|
||||
@NamedQuery(name = ResourceSet.QUERY_BY_OWNER_AND_CLIENT, query = "select r from ResourceSet r where r.owner = :" + ResourceSet.PARAM_OWNER + " and r.clientId = :" + ResourceSet.PARAM_CLIENTID)
|
||||
})
|
||||
public class ResourceSet {
|
||||
|
||||
public static final String QUERY_BY_OWNER = "ResourceSet.queryByOwner";
|
||||
public static final String QUERY_BY_OWNER_AND_CLIENT = "ResourceSet.queryByOwnerAndClient";
|
||||
|
||||
public static final String PARAM_OWNER = "owner";
|
||||
public static final String PARAM_CLIENTID = "clientId";
|
||||
|
||||
private Long id;
|
||||
private String name;
|
||||
private String uri;
|
||||
private String type;
|
||||
private Set<String> scopes;
|
||||
private String iconUri;
|
||||
|
||||
private String owner; // username of the person responsible for the registration (either directly or via OAuth token)
|
||||
private String clientId; // client id of the protected resource that registered this resource set via OAuth token
|
||||
|
||||
private Collection<Claim> claimsRequired;
|
||||
|
||||
/**
|
||||
* @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 name
|
||||
*/
|
||||
@Basic
|
||||
@Column(name = "name")
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name the name to set
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the uri
|
||||
*/
|
||||
@Basic
|
||||
@Column(name = "uri")
|
||||
public String getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri the uri to set
|
||||
*/
|
||||
public void setUri(String uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the type
|
||||
*/
|
||||
@Basic
|
||||
@Column(name = "rs_type")
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type the type to set
|
||||
*/
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the scopes
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@Column(name = "scope")
|
||||
@CollectionTable(
|
||||
name = "resource_set_scope",
|
||||
joinColumns = @JoinColumn(name = "owner_id")
|
||||
)
|
||||
public Set<String> getScopes() {
|
||||
return scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param scopes the scopes to set
|
||||
*/
|
||||
public void setScopes(Set<String> scopes) {
|
||||
this.scopes = scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the iconUri
|
||||
*/
|
||||
@Basic
|
||||
@Column(name = "icon_uri")
|
||||
public String getIconUri() {
|
||||
return iconUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param iconUri the iconUri to set
|
||||
*/
|
||||
public void setIconUri(String iconUri) {
|
||||
this.iconUri = iconUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the owner
|
||||
*/
|
||||
@Basic
|
||||
@Column(name = "owner")
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param owner the owner to set
|
||||
*/
|
||||
public void setOwner(String owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 claimsRequired
|
||||
*/
|
||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "resource_set_id")
|
||||
public Collection<Claim> getClaimsRequired() {
|
||||
return claimsRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param claimsRequired the claimsRequired to set
|
||||
*/
|
||||
public void setClaimsRequired(Collection<Claim> claimsRequired) {
|
||||
this.claimsRequired = claimsRequired;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -14,23 +14,32 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
package org.mitre.oauth2.service;
|
||||
|
||||
import java.util.Set;
|
||||
package org.mitre.uma.repository;
|
||||
|
||||
import org.springframework.security.oauth2.provider.ClientDetails;
|
||||
import org.mitre.uma.model.PermissionTicket;
|
||||
|
||||
/**
|
||||
* Strategy interface used for authorizing token introspection.
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
public interface IntrospectionAuthorizer {
|
||||
public interface PermissionRepository {
|
||||
|
||||
/**
|
||||
* @param authClient the authenticated client wanting to perform token introspection
|
||||
* @param tokenClient the client the token was issued to
|
||||
* @param tokenScope the scope associated with the token
|
||||
* @return {@code true} in case introspection is permitted; {@code false} otherwise
|
||||
*
|
||||
* Save a permission ticket.
|
||||
*
|
||||
* @param p
|
||||
* @return
|
||||
*/
|
||||
boolean isIntrospectionPermitted(ClientDetails authClient, ClientDetails tokenClient, Set<String> tokenScope);
|
||||
public PermissionTicket save(PermissionTicket p);
|
||||
|
||||
/**
|
||||
* Get the permission indicated by its ticket value.
|
||||
*
|
||||
* @param ticket
|
||||
* @return
|
||||
*/
|
||||
public PermissionTicket getByTicket(String ticket);
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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 java.util.Collection;
|
||||
|
||||
import org.mitre.uma.model.ResourceSet;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
public interface ResourceSetRepository {
|
||||
|
||||
public ResourceSet save(ResourceSet rs);
|
||||
|
||||
public ResourceSet getById(Long id);
|
||||
|
||||
public void remove(ResourceSet rs);
|
||||
|
||||
public Collection<ResourceSet> getAllForOwner(String owner);
|
||||
|
||||
public Collection<ResourceSet> getAllForOwnerAndClient(String owner, String clientId);
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.service;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mitre.uma.model.Claim;
|
||||
|
||||
/**
|
||||
*
|
||||
* Processes claims presented during an UMA transaction.
|
||||
*
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
public interface ClaimsProcessingService {
|
||||
|
||||
/**
|
||||
*
|
||||
* Determine whether or not the claims that have been supplied are
|
||||
* sufficient to fulfill the requirements given by the claims that
|
||||
* are required.
|
||||
*
|
||||
* @param claimsRequired the required claims to check against
|
||||
* @param claimsSupplied the supplied claims to test
|
||||
* @return the unmatched claims (if any), an empty set if the claims are satisfied, never null
|
||||
*/
|
||||
public Collection<Claim> claimsAreSatisfied(Collection<Claim> claimsRequired, Collection<Claim> claimsSupplied);
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.service;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.mitre.uma.model.PermissionTicket;
|
||||
import org.mitre.uma.model.ResourceSet;
|
||||
import org.springframework.security.oauth2.common.exceptions.InsufficientScopeException;
|
||||
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
public interface PermissionService {
|
||||
|
||||
/**
|
||||
* @param resourceSet the resource set to create the permission on
|
||||
* @param scopes the set of scopes that this permission is for
|
||||
* @return the created (and stored) permission object, with ticket
|
||||
* @throws InsufficientScopeException if the scopes in scopes don't match those in resourceSet.getScopes
|
||||
*/
|
||||
public PermissionTicket createTicket(ResourceSet resourceSet, Set<String> scopes);
|
||||
|
||||
/**
|
||||
*
|
||||
* Read the permission associated with the given ticket.
|
||||
*
|
||||
* @param the ticket value to search on
|
||||
* @return the permission object, or null if none is found
|
||||
*/
|
||||
public PermissionTicket getByTicket(String ticket);
|
||||
|
||||
/**
|
||||
* Save the updated permission ticket to the database. Does not create a new ticket.
|
||||
*
|
||||
* @param ticket
|
||||
* @return
|
||||
*/
|
||||
public PermissionTicket updateTicket(PermissionTicket ticket);
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.service;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mitre.uma.model.ResourceSet;
|
||||
|
||||
/**
|
||||
*
|
||||
* Manage registered resource sets at this authorization server.
|
||||
*
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
public interface ResourceSetService {
|
||||
|
||||
public ResourceSet saveNew(ResourceSet rs);
|
||||
|
||||
public ResourceSet getById(Long id);
|
||||
|
||||
public ResourceSet update(ResourceSet oldRs, ResourceSet newRs);
|
||||
|
||||
public void remove(ResourceSet rs);
|
||||
|
||||
public Collection<ResourceSet> getAllForOwner(String owner);
|
||||
|
||||
public Collection<ResourceSet> getAllForOwnerAndClient(String owner, String authClientId);
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.service;
|
||||
|
||||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||
import org.mitre.uma.model.PermissionTicket;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
|
||||
/**
|
||||
* Service to create special tokens for UMA.
|
||||
*
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
public interface UmaTokenService {
|
||||
|
||||
/**
|
||||
* Create the RPT from the given authentication and ticket.
|
||||
*
|
||||
* @param o2auth
|
||||
* @param ticket
|
||||
* @return
|
||||
*/
|
||||
public OAuth2AccessTokenEntity createRequestingPartyToken(OAuth2Authentication o2auth, PermissionTicket ticket);
|
||||
|
||||
}
|
|
@ -158,6 +158,22 @@ public class JsonUtils {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the given member as a Long, null if it doesn't exist
|
||||
*/
|
||||
public static Long getAsLong(JsonObject o, String member) {
|
||||
if (o.has(member)) {
|
||||
JsonElement e = o.get(member);
|
||||
if (e != null && e.isJsonPrimitive()) {
|
||||
return e.getAsLong();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the given given member as a set of strings, null if it doesn't exist
|
||||
|
|
|
@ -14,6 +14,11 @@ CREATE TABLE IF NOT EXISTS access_token (
|
|||
approved_site_id BIGINT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS access_token_permissions (
|
||||
access_token_id BIGINT NOT NULL,
|
||||
permission_id BIGINT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS address (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY,
|
||||
formatted VARCHAR(256),
|
||||
|
@ -219,3 +224,55 @@ CREATE TABLE IF NOT EXISTS pairwise_identifier (
|
|||
sub VARCHAR(256),
|
||||
sector_identifier VARCHAR(2048)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS resource_set (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY,
|
||||
name VARCHAR(1024) NOT NULL,
|
||||
uri VARCHAR(1024),
|
||||
icon_uri VARCHAR(1024),
|
||||
rs_type VARCHAR(256),
|
||||
owner VARCHAR(256) NOT NULL,
|
||||
client_id VARCHAR(256)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS resource_set_scope (
|
||||
owner_id BIGINT NOT NULL,
|
||||
scope VARCHAR(256) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS permission_ticket (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY,
|
||||
ticket VARCHAR(256) NOT NULL,
|
||||
permission_id BIGINT NOT NULL,
|
||||
expiration TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS permission (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY,
|
||||
resource_set_id BIGINT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS permission_scope (
|
||||
owner_id BIGINT NOT NULL,
|
||||
scope VARCHAR(256) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS claim (
|
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY,
|
||||
name VARCHAR(256),
|
||||
friendly_name VARCHAR(1024),
|
||||
claim_type VARCHAR(1024),
|
||||
claim_value VARCHAR(1024),
|
||||
resource_set_id BIGINT,
|
||||
permission_ticket_id BIGINT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS claim_token_format (
|
||||
owner_id BIGINT NOT NULL,
|
||||
claim_token_format VARCHAR(1024)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS claim_issuer (
|
||||
owner_id BIGINT NOT NULL,
|
||||
issuer VARCHAR(1024)
|
||||
);
|
||||
|
|
|
@ -8,12 +8,17 @@ CREATE TABLE IF NOT EXISTS access_token (
|
|||
expiration TIMESTAMP NULL,
|
||||
token_type VARCHAR(256),
|
||||
refresh_token_id BIGINT,
|
||||
client_id VARCHAR(256),
|
||||
client_id BIGINT,
|
||||
auth_holder_id BIGINT,
|
||||
id_token_id BIGINT,
|
||||
approved_site_id BIGINT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS access_token_permissions (
|
||||
access_token_id BIGINT NOT NULL,
|
||||
permission_id BIGINT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS address (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
formatted VARCHAR(256),
|
||||
|
@ -219,3 +224,55 @@ CREATE TABLE IF NOT EXISTS pairwise_identifier (
|
|||
sub VARCHAR(256),
|
||||
sector_identifier VARCHAR(2048)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS resource_set (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(1024) NOT NULL,
|
||||
uri VARCHAR(1024),
|
||||
icon_uri VARCHAR(1024),
|
||||
rs_type VARCHAR(256),
|
||||
owner VARCHAR(256) NOT NULL,
|
||||
client_id VARCHAR(256)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS resource_set_scope (
|
||||
owner_id BIGINT NOT NULL,
|
||||
scope VARCHAR(256) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS permission_ticket (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
ticket VARCHAR(256) NOT NULL,
|
||||
permission_id BIGINT NOT NULL,
|
||||
expiration TIMESTAMP NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS permission (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
resource_set_id BIGINT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS permission_scope (
|
||||
owner_id BIGINT NOT NULL,
|
||||
scope VARCHAR(256) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS claim (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(256),
|
||||
friendly_name VARCHAR(1024),
|
||||
claim_type VARCHAR(1024),
|
||||
claim_value VARCHAR(1024),
|
||||
resource_set_id BIGINT,
|
||||
permission_ticket_id BIGINT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS claim_token_format (
|
||||
owner_id BIGINT NOT NULL,
|
||||
claim_token_format VARCHAR(1024)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS claim_issuer (
|
||||
owner_id BIGINT NOT NULL,
|
||||
issuer VARCHAR(1024)
|
||||
);
|
||||
|
|
|
@ -79,8 +79,8 @@
|
|||
"id-token-signing-algorithm": "ID Token Signing Algorithm",
|
||||
"id-token-timeout": "ID Token Timeout",
|
||||
"implicit": "implicit",
|
||||
"intiate-login": "Intiate Login",
|
||||
"intiate-login-help": "URL to initiate login on the client",
|
||||
"initiate-login": "Initiate Login",
|
||||
"initiate-login-help": "URL to initiate login on the client",
|
||||
"introspection": "Introspection",
|
||||
"jwk-set": "JWK Set",
|
||||
"jwk-set-help": "URL for the client's JSON Web Key set",
|
||||
|
|
|
@ -86,13 +86,13 @@ var WhiteListListView = Backbone.View.extend({
|
|||
_.each(this.model.models, function (whiteList) {
|
||||
|
||||
// look up client
|
||||
var client = this.options.clientList.getByClientId(whiteList.get('clientId'));
|
||||
var client = _self.options.clientList.getByClientId(whiteList.get('clientId'));
|
||||
|
||||
// if there's no client ID, this is an error!
|
||||
if (client != null) {
|
||||
var view = new WhiteListView({model: whiteList, client: client, systemScopeList: this.options.systemScopeList});
|
||||
var view = new WhiteListView({model: whiteList, client: client, systemScopeList: _self.options.systemScopeList});
|
||||
view.parentView = _self;
|
||||
$('#whitelist-table', this.el).append(view.render().el);
|
||||
$('#whitelist-table', _self.el).append(view.render().el);
|
||||
}
|
||||
|
||||
}, this);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*******************************************************************************/
|
||||
package org.mitre.discovery.web;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -289,6 +290,7 @@ public class DiscoveryEndpoint {
|
|||
Collection<JWSAlgorithm> clientSymmetricSigningAlgs = Lists.newArrayList(JWSAlgorithm.HS256, JWSAlgorithm.HS384, JWSAlgorithm.HS512);
|
||||
Collection<JWSAlgorithm> clientSymmetricAndAsymmetricSigningAlgs = Lists.newArrayList(JWSAlgorithm.HS256, JWSAlgorithm.HS384, JWSAlgorithm.HS512, JWSAlgorithm.RS256, JWSAlgorithm.RS384, JWSAlgorithm.RS512);
|
||||
Collection<Algorithm> clientSymmetricAndAsymmetricSigningAlgsWithNone = Lists.newArrayList(JWSAlgorithm.HS256, JWSAlgorithm.HS384, JWSAlgorithm.HS512, JWSAlgorithm.RS256, JWSAlgorithm.RS384, JWSAlgorithm.RS512, Algorithm.NONE);
|
||||
ArrayList<String> grantTypes = Lists.newArrayList("authorization_code", "implicit", "urn:ietf:params:oauth:grant-type:jwt-bearer", "client_credentials", "urn:ietf:params:oauth:grant_type:redelegate");
|
||||
|
||||
Map<String, Object> m = new HashMap<String, Object>();
|
||||
m.put("issuer", config.getIssuer());
|
||||
|
@ -301,7 +303,7 @@ public class DiscoveryEndpoint {
|
|||
m.put("registration_endpoint", baseUrl + DynamicClientRegistrationEndpoint.URL);
|
||||
m.put("scopes_supported", scopeService.toStrings(scopeService.getUnrestricted())); // these are the scopes that you can dynamically register for, which is what matters for discovery
|
||||
m.put("response_types_supported", Lists.newArrayList("code", "token")); // we don't support these yet: , "id_token", "id_token token"));
|
||||
m.put("grant_types_supported", Lists.newArrayList("authorization_code", "implicit", "urn:ietf:params:oauth:grant-type:jwt-bearer", "client_credentials", "urn:ietf:params:oauth:grant_type:redelegate"));
|
||||
m.put("grant_types_supported", grantTypes);
|
||||
//acr_values_supported
|
||||
m.put("subject_types_supported", Lists.newArrayList("public", "pairwise"));
|
||||
m.put("userinfo_signing_alg_values_supported", Collections2.transform(clientSymmetricAndAsymmetricSigningAlgs, toAlgorithmName));
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.oauth2.service.impl;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.mitre.oauth2.service.IntrospectionAuthorizer;
|
||||
import org.mitre.oauth2.service.SystemScopeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.oauth2.provider.ClientDetails;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class DefaultIntrospectionAuthorizer implements IntrospectionAuthorizer {
|
||||
|
||||
@Autowired
|
||||
private SystemScopeService scopeService;
|
||||
|
||||
@Override
|
||||
public boolean isIntrospectionPermitted(ClientDetails authClient,
|
||||
ClientDetails tokenClient, Set<String> tokenScope) {
|
||||
// permit introspection if it's the same client that the token was
|
||||
// issued to, or it at least has all the scopes the token was issued
|
||||
// with
|
||||
return authClient.getClientId().equals(tokenClient.getClientId())
|
||||
|| scopeService.scopesMatch(authClient.getScope(), tokenScope);
|
||||
}
|
||||
|
||||
}
|
|
@ -18,17 +18,20 @@ package org.mitre.oauth2.service.impl;
|
|||
|
||||
import java.text.ParseException;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||
import org.mitre.oauth2.model.OAuth2RefreshTokenEntity;
|
||||
import org.mitre.oauth2.service.IntrospectionResultAssembler;
|
||||
import org.mitre.openid.connect.model.UserInfo;
|
||||
import org.mitre.uma.model.Permission;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import static com.google.common.collect.Maps.newLinkedHashMap;
|
||||
|
||||
|
@ -44,14 +47,33 @@ public class DefaultIntrospectionResultAssembler implements IntrospectionResultA
|
|||
private static final Logger logger = LoggerFactory.getLogger(DefaultIntrospectionResultAssembler.class);
|
||||
|
||||
@Override
|
||||
public Map<String, Object> assembleFrom(OAuth2AccessTokenEntity accessToken, UserInfo userInfo) {
|
||||
public Map<String, Object> assembleFrom(OAuth2AccessTokenEntity accessToken, UserInfo userInfo, Set<String> authScopes) {
|
||||
|
||||
Map<String, Object> result = newLinkedHashMap();
|
||||
OAuth2Authentication authentication = accessToken.getAuthenticationHolder().getAuthentication();
|
||||
|
||||
result.put(ACTIVE, true);
|
||||
|
||||
result.put(SCOPE, Joiner.on(SCOPE_SEPARATOR).join(accessToken.getScope()));
|
||||
if (accessToken.getPermissions() != null && !accessToken.getPermissions().isEmpty()) {
|
||||
|
||||
Set<Object> permissions = Sets.newHashSet();
|
||||
|
||||
for (Permission perm : accessToken.getPermissions()) {
|
||||
Map<String, Object> o = newLinkedHashMap();
|
||||
o.put("resource_set_id", perm.getResourceSet().getId().toString());
|
||||
Set<String> scopes = Sets.newHashSet(perm.getScopes());
|
||||
o.put("scopes", scopes);
|
||||
permissions.add(o);
|
||||
}
|
||||
|
||||
result.put("permissions", permissions);
|
||||
|
||||
} else {
|
||||
Set<String> scopes = Sets.intersection(authScopes, accessToken.getScope());
|
||||
|
||||
result.put(SCOPE, Joiner.on(SCOPE_SEPARATOR).join(scopes));
|
||||
|
||||
}
|
||||
|
||||
if (accessToken.getExpiration() != null) {
|
||||
try {
|
||||
|
@ -80,14 +102,16 @@ public class DefaultIntrospectionResultAssembler implements IntrospectionResultA
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> assembleFrom(OAuth2RefreshTokenEntity refreshToken, UserInfo userInfo) {
|
||||
public Map<String, Object> assembleFrom(OAuth2RefreshTokenEntity refreshToken, UserInfo userInfo, Set<String> authScopes) {
|
||||
|
||||
Map<String, Object> result = newLinkedHashMap();
|
||||
OAuth2Authentication authentication = refreshToken.getAuthenticationHolder().getAuthentication();
|
||||
|
||||
result.put(ACTIVE, true);
|
||||
|
||||
result.put(SCOPE, Joiner.on(SCOPE_SEPARATOR).join(authentication.getOAuth2Request().getScope()));
|
||||
Set<String> scopes = Sets.intersection(authScopes, authentication.getOAuth2Request().getScope());
|
||||
|
||||
result.put(SCOPE, Joiner.on(SCOPE_SEPARATOR).join(scopes));
|
||||
|
||||
if (refreshToken.getExpiration() != null) {
|
||||
try {
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.oauth2.web;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.oauth2.common.exceptions.InsufficientScopeException;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
*
|
||||
* Utility class to enforce OAuth scopes in authenticated requests.
|
||||
*
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
public abstract class AuthenticationUtilities {
|
||||
|
||||
/**
|
||||
* Makes sure the authentication contains the given scope, throws an exception otherwise
|
||||
* @param auth the authentication object to check
|
||||
* @param scope the scope to look for
|
||||
* @throws InsufficientScopeException if the authentication does not contain that scope
|
||||
*/
|
||||
public static void ensureOAuthScope(Authentication auth, String scope) {
|
||||
// if auth is OAuth, make sure we've got the right scope
|
||||
if (auth instanceof OAuth2Authentication) {
|
||||
OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) auth;
|
||||
if (oAuth2Authentication.getOAuth2Request().getScope() == null
|
||||
|| !oAuth2Authentication.getOAuth2Request().getScope().contains(scope)) {
|
||||
throw new InsufficientScopeException("Insufficient scope", ImmutableSet.of(scope));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the given auth object has ROLE_ADMIN assigned to it or not
|
||||
* @param auth
|
||||
* @return
|
||||
*/
|
||||
public static boolean isAdmin(Authentication auth) {
|
||||
for (GrantedAuthority grantedAuthority : auth.getAuthorities()) {
|
||||
if (grantedAuthority.getAuthority().equals("ROLE_ADMIN")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static boolean hasRole(Authentication auth, String role) {
|
||||
for (GrantedAuthority grantedAuthority : auth.getAuthorities()) {
|
||||
if (grantedAuthority.getAuthority().equals(role)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -16,7 +16,8 @@
|
|||
*******************************************************************************/
|
||||
package org.mitre.oauth2.web;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -24,21 +25,24 @@ import org.mitre.oauth2.model.ClientDetailsEntity;
|
|||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||
import org.mitre.oauth2.model.OAuth2RefreshTokenEntity;
|
||||
import org.mitre.oauth2.service.ClientDetailsEntityService;
|
||||
import org.mitre.oauth2.service.IntrospectionAuthorizer;
|
||||
import org.mitre.oauth2.service.IntrospectionResultAssembler;
|
||||
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
||||
import org.mitre.oauth2.service.SystemScopeService;
|
||||
import org.mitre.openid.connect.model.UserInfo;
|
||||
import org.mitre.openid.connect.service.UserInfoService;
|
||||
import org.mitre.openid.connect.view.HttpCodeView;
|
||||
import org.mitre.openid.connect.view.JsonEntityView;
|
||||
import org.mitre.uma.model.ResourceSet;
|
||||
import org.mitre.uma.service.ResourceSetService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
|
||||
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
|
@ -49,6 +53,8 @@ import org.springframework.web.bind.annotation.RequestParam;
|
|||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import static org.mitre.oauth2.web.AuthenticationUtilities.ensureOAuthScope;
|
||||
|
||||
@Controller
|
||||
public class IntrospectionEndpoint {
|
||||
|
||||
|
@ -63,14 +69,14 @@ public class IntrospectionEndpoint {
|
|||
@Autowired
|
||||
private ClientDetailsEntityService clientService;
|
||||
|
||||
@Autowired
|
||||
private IntrospectionAuthorizer introspectionAuthorizer;
|
||||
|
||||
@Autowired
|
||||
private IntrospectionResultAssembler introspectionResultAssembler;
|
||||
|
||||
@Autowired
|
||||
private UserInfoService userInfoService;
|
||||
|
||||
@Autowired
|
||||
private ResourceSetService resourceSetService;
|
||||
|
||||
@Autowired
|
||||
private WebResponseExceptionTranslator providerExceptionHandler;
|
||||
|
@ -88,13 +94,62 @@ public class IntrospectionEndpoint {
|
|||
this.tokenServices = tokenServices;
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_CLIENT')")
|
||||
@RequestMapping("/" + URL)
|
||||
public String verify(@RequestParam("token") String tokenValue,
|
||||
@RequestParam(value = "resource_id", required = false) String resourceId,
|
||||
@RequestParam(value = "token_type_hint", required = false) String tokenType,
|
||||
Principal p, Model model) {
|
||||
Authentication auth, Model model) {
|
||||
|
||||
ClientDetailsEntity authClient = null;
|
||||
Set<String> authScopes = new HashSet<>();
|
||||
|
||||
if (auth instanceof OAuth2Authentication) {
|
||||
// the client authenticated with OAuth, do our UMA checks
|
||||
ensureOAuthScope(auth, SystemScopeService.UMA_PROTECTION_SCOPE);
|
||||
|
||||
// get out the client that was issued the access token (not the token being introspected)
|
||||
OAuth2Authentication o2a = (OAuth2Authentication) auth;
|
||||
|
||||
String authClientId = o2a.getOAuth2Request().getClientId();
|
||||
authClient = clientService.loadClientByClientId(authClientId);
|
||||
|
||||
// the owner is the user who authorized the token in the first place
|
||||
String ownerId = o2a.getUserAuthentication().getName();
|
||||
|
||||
authScopes.addAll(authClient.getScope());
|
||||
|
||||
// UMA style clients also get a subset of scopes of all the resource sets they've registered
|
||||
Collection<ResourceSet> resourceSets = resourceSetService.getAllForOwnerAndClient(ownerId, authClientId);
|
||||
|
||||
// collect all the scopes
|
||||
for (ResourceSet rs : resourceSets) {
|
||||
authScopes.addAll(rs.getScopes());
|
||||
}
|
||||
|
||||
} else {
|
||||
// the client authenticated directly, make sure it's got the right access
|
||||
|
||||
String authClientId = auth.getName(); // direct authentication puts the client_id into the authentication's name field
|
||||
authClient = clientService.loadClientByClientId(authClientId);
|
||||
|
||||
// directly authenticated clients get a subset of any scopes that they've registered for
|
||||
authScopes.addAll(authClient.getScope());
|
||||
|
||||
if (!AuthenticationUtilities.hasRole(auth, "ROLE_CLIENT")
|
||||
|| !authClient.isAllowIntrospection()) {
|
||||
|
||||
// this client isn't allowed to do direct introspection
|
||||
|
||||
logger.error("Client " + authClient.getClientId() + " is not allowed to call introspection endpoint");
|
||||
model.addAttribute("code", HttpStatus.FORBIDDEN);
|
||||
return HttpCodeView.VIEWNAME;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// by here we're allowed to introspect, now we need to look up the token in our token stores
|
||||
|
||||
// first make sure the token is there
|
||||
if (Strings.isNullOrEmpty(tokenValue)) {
|
||||
logger.error("Verify failed; token value is null");
|
||||
Map<String,Boolean> entity = ImmutableMap.of("active", Boolean.FALSE);
|
||||
|
@ -105,7 +160,6 @@ public class IntrospectionEndpoint {
|
|||
OAuth2AccessTokenEntity accessToken = null;
|
||||
OAuth2RefreshTokenEntity refreshToken = null;
|
||||
ClientDetailsEntity tokenClient;
|
||||
Set<String> scopes;
|
||||
UserInfo user;
|
||||
|
||||
try {
|
||||
|
@ -114,53 +168,50 @@ public class IntrospectionEndpoint {
|
|||
accessToken = tokenServices.readAccessToken(tokenValue);
|
||||
|
||||
tokenClient = accessToken.getClient();
|
||||
scopes = accessToken.getScope();
|
||||
|
||||
user = userInfoService.getByUsernameAndClientId(accessToken.getAuthenticationHolder().getAuthentication().getName(), tokenClient.getClientId());
|
||||
// get the user information of the user that authorized this token in the first place
|
||||
String userName = accessToken.getAuthenticationHolder().getAuthentication().getName();
|
||||
user = userInfoService.getByUsernameAndClientId(userName, tokenClient.getClientId());
|
||||
|
||||
} catch (InvalidTokenException e) {
|
||||
logger.info("Verify failed; Invalid access token. Checking refresh token.");
|
||||
logger.info("Invalid access token. Checking refresh token.");
|
||||
try {
|
||||
|
||||
// check refresh tokens next
|
||||
refreshToken = tokenServices.getRefreshToken(tokenValue);
|
||||
|
||||
tokenClient = refreshToken.getClient();
|
||||
scopes = refreshToken.getAuthenticationHolder().getAuthentication().getOAuth2Request().getScope();
|
||||
|
||||
user = userInfoService.getByUsernameAndClientId(refreshToken.getAuthenticationHolder().getAuthentication().getName(), tokenClient.getClientId());
|
||||
// get the user information of the user that authorized this token in the first place
|
||||
String userName = refreshToken.getAuthenticationHolder().getAuthentication().getName();
|
||||
user = userInfoService.getByUsernameAndClientId(userName, tokenClient.getClientId());
|
||||
|
||||
} catch (InvalidTokenException e2) {
|
||||
logger.error("Verify failed; Invalid access/refresh token", e2);
|
||||
Map<String,Boolean> entity = ImmutableMap.of("active", Boolean.FALSE);
|
||||
logger.error("Invalid refresh token");
|
||||
Map<String,Boolean> entity = ImmutableMap.of(IntrospectionResultAssembler.ACTIVE, Boolean.FALSE);
|
||||
model.addAttribute(JsonEntityView.ENTITY, entity);
|
||||
return JsonEntityView.VIEWNAME;
|
||||
}
|
||||
}
|
||||
|
||||
// clientID is the principal name in the authentication
|
||||
String clientId = p.getName();
|
||||
ClientDetailsEntity authClient = clientService.loadClientByClientId(clientId);
|
||||
|
||||
if (authClient.isAllowIntrospection()) {
|
||||
if (introspectionAuthorizer.isIntrospectionPermitted(authClient, tokenClient, scopes)) {
|
||||
// if it's a valid token, we'll print out information on it
|
||||
Map<String, Object> entity = accessToken != null
|
||||
? introspectionResultAssembler.assembleFrom(accessToken, user)
|
||||
: introspectionResultAssembler.assembleFrom(refreshToken, user);
|
||||
model.addAttribute(JsonEntityView.ENTITY, entity);
|
||||
return JsonEntityView.VIEWNAME;
|
||||
} else {
|
||||
logger.error("Verify failed; client configuration or scope don't permit token introspection");
|
||||
model.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN);
|
||||
return HttpCodeView.VIEWNAME;
|
||||
}
|
||||
// if it's a valid token, we'll print out information on it
|
||||
|
||||
if (accessToken != null) {
|
||||
Map<String, Object> entity = introspectionResultAssembler.assembleFrom(accessToken, user, authScopes);
|
||||
model.addAttribute(JsonEntityView.ENTITY, entity);
|
||||
} else if (refreshToken != null) {
|
||||
Map<String, Object> entity = introspectionResultAssembler.assembleFrom(refreshToken, user, authScopes);
|
||||
model.addAttribute(JsonEntityView.ENTITY, entity);
|
||||
} else {
|
||||
logger.error("Verify failed; client " + clientId + " is not allowed to call introspection endpoint");
|
||||
model.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN);
|
||||
return HttpCodeView.VIEWNAME;
|
||||
// no tokens were found (we shouldn't get here)
|
||||
logger.error("Verify failed; Invalid access/refresh token");
|
||||
Map<String,Boolean> entity = ImmutableMap.of(IntrospectionResultAssembler.ACTIVE, Boolean.FALSE);
|
||||
model.addAttribute(JsonEntityView.ENTITY, entity);
|
||||
return JsonEntityView.VIEWNAME;
|
||||
}
|
||||
|
||||
|
||||
return JsonEntityView.VIEWNAME;
|
||||
|
||||
}
|
||||
|
||||
@ExceptionHandler(OAuth2Exception.class)
|
||||
|
|
|
@ -179,8 +179,6 @@ public class ConnectOAuth2RequestFactory extends DefaultOAuth2RequestFactory {
|
|||
try {
|
||||
JWT jwt = JWTParser.parse(jwtString);
|
||||
|
||||
// TODO: move keys to constants
|
||||
|
||||
if (jwt instanceof SignedJWT) {
|
||||
// it's a signed JWT, check the signature
|
||||
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.openid.connect.request;
|
||||
|
||||
public interface ConnectRequestParameters {
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.openid.connect.service.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.mitre.uma.model.ResourceSet;
|
||||
import org.mitre.uma.service.ResourceSetService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* Dummy resource set service that doesn't do anything; acts as a stub for the
|
||||
* introspection service when the UMA functionality is disabled.
|
||||
*
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Service
|
||||
public class DummyResourceSetService implements ResourceSetService {
|
||||
|
||||
@Override
|
||||
public ResourceSet saveNew(ResourceSet rs) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceSet getById(Long id) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceSet update(ResourceSet oldRs, ResourceSet newRs) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(ResourceSet rs) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourceSet> getAllForOwner(String owner) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourceSet> getAllForOwnerAndClient(String owner, String authClientId) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,3 +1,19 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.openid.connect.service.impl;
|
||||
|
||||
import java.text.ParseException;
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.mitre.jose.JWSAlgorithmEmbed;
|
|||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod;
|
||||
import org.mitre.oauth2.service.ClientDetailsEntityService;
|
||||
import org.mitre.oauth2.web.AuthenticationUtilities;
|
||||
import org.mitre.openid.connect.service.UserInfoService;
|
||||
import org.mitre.openid.connect.view.ClientEntityViewForAdmins;
|
||||
import org.mitre.openid.connect.view.ClientEntityViewForUsers;
|
||||
|
@ -135,7 +136,7 @@ public class ClientAPI {
|
|||
Collection<ClientDetailsEntity> clients = clientService.getAllClients();
|
||||
model.addAttribute(JsonEntityView.ENTITY, clients);
|
||||
|
||||
if (isAdmin(auth)) {
|
||||
if (AuthenticationUtilities.isAdmin(auth)) {
|
||||
return ClientEntityViewForAdmins.VIEWNAME;
|
||||
} else {
|
||||
return ClientEntityViewForUsers.VIEWNAME;
|
||||
|
@ -220,7 +221,7 @@ public class ClientAPI {
|
|||
ClientDetailsEntity newClient = clientService.saveNewClient(client);
|
||||
m.addAttribute(JsonEntityView.ENTITY, newClient);
|
||||
|
||||
if (isAdmin(auth)) {
|
||||
if (AuthenticationUtilities.isAdmin(auth)) {
|
||||
return ClientEntityViewForAdmins.VIEWNAME;
|
||||
} else {
|
||||
return ClientEntityViewForUsers.VIEWNAME;
|
||||
|
@ -314,7 +315,7 @@ public class ClientAPI {
|
|||
ClientDetailsEntity newClient = clientService.updateClient(oldClient, client);
|
||||
m.addAttribute(JsonEntityView.ENTITY, newClient);
|
||||
|
||||
if (isAdmin(auth)) {
|
||||
if (AuthenticationUtilities.isAdmin(auth)) {
|
||||
return ClientEntityViewForAdmins.VIEWNAME;
|
||||
} else {
|
||||
return ClientEntityViewForUsers.VIEWNAME;
|
||||
|
@ -367,27 +368,13 @@ public class ClientAPI {
|
|||
|
||||
model.addAttribute(JsonEntityView.ENTITY, client);
|
||||
|
||||
if (isAdmin(auth)) {
|
||||
if (AuthenticationUtilities.isAdmin(auth)) {
|
||||
return ClientEntityViewForAdmins.VIEWNAME;
|
||||
} else {
|
||||
return ClientEntityViewForUsers.VIEWNAME;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the given auth object has ROLE_ADMIN assigned to it or not
|
||||
* @param auth
|
||||
* @return
|
||||
*/
|
||||
private boolean isAdmin(Authentication auth) {
|
||||
for (GrantedAuthority grantedAuthority : auth.getAuthorities()) {
|
||||
if (grantedAuthority.getAuthority().equals("ROLE_ADMIN")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ExceptionHandler(OAuth2Exception.class)
|
||||
public ResponseEntity<OAuth2Exception> handleException(Exception e) throws Exception {
|
||||
logger.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
|
||||
|
|
|
@ -1,116 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.oauth2.service.impl;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mitre.oauth2.service.SystemScopeService;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.security.oauth2.provider.ClientDetails;
|
||||
|
||||
import static com.google.common.collect.Sets.newHashSet;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
|
||||
import static org.mockito.BDDMockito.given;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class TestDefaultIntrospectionAuthorizer {
|
||||
|
||||
@InjectMocks
|
||||
private DefaultIntrospectionAuthorizer introspectionPermitter;
|
||||
|
||||
@Mock
|
||||
private SystemScopeService scopeService;
|
||||
|
||||
@Test
|
||||
public void shouldPermitIntrospectionToSameClientTheTokenWasIssuedTo() {
|
||||
|
||||
// given
|
||||
String sameClient = "same";
|
||||
|
||||
// when
|
||||
boolean permitted = introspectionPermitter.isIntrospectionPermitted(
|
||||
clientWithId(sameClient), clientWithId(sameClient),
|
||||
scope("scope"));
|
||||
|
||||
// then
|
||||
assertThat(permitted, is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPermitIntrospectionToDifferentClientIfScopesMatch() {
|
||||
|
||||
// given
|
||||
String authClient = "auth";
|
||||
String tokenClient = "token";
|
||||
Set<String> authScope = scope("scope1", "scope2", "scope3");
|
||||
Set<String> tokenScope = scope("scope1", "scope2");
|
||||
given(scopeService.scopesMatch(authScope, tokenScope)).willReturn(true);
|
||||
|
||||
// when
|
||||
boolean permitted = introspectionPermitter.isIntrospectionPermitted(
|
||||
clientWithIdAndScope(authClient, authScope),
|
||||
clientWithId(tokenClient), tokenScope);
|
||||
|
||||
// then
|
||||
assertThat(permitted, is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotPermitIntrospectionToDifferentClientIfScopesDontMatch() {
|
||||
|
||||
// given
|
||||
String authClient = "auth";
|
||||
String tokenClient = "token";
|
||||
Set<String> authScope = scope("scope1", "scope2");
|
||||
Set<String> tokenScope = scope("scope1", "scope2", "scope3");
|
||||
given(scopeService.scopesMatch(authScope, tokenScope)).willReturn(false);
|
||||
|
||||
// when
|
||||
boolean permitted = introspectionPermitter.isIntrospectionPermitted(
|
||||
clientWithIdAndScope(authClient, authScope),
|
||||
clientWithId(tokenClient), tokenScope);
|
||||
|
||||
// then
|
||||
assertThat(permitted, is(false));
|
||||
}
|
||||
|
||||
private ClientDetails clientWithId(String clientId) {
|
||||
ClientDetails client = mock(ClientDetails.class);
|
||||
given(client.getClientId()).willReturn(clientId);
|
||||
return client;
|
||||
}
|
||||
|
||||
private ClientDetails clientWithIdAndScope(String clientId, Set<String> scope) {
|
||||
ClientDetails client = clientWithId(clientId);
|
||||
given(client.getScope()).willReturn(scope);
|
||||
return client;
|
||||
}
|
||||
|
||||
private Set<String> scope(String... scopeItems) {
|
||||
return newHashSet(scopeItems);
|
||||
}
|
||||
}
|
|
@ -29,10 +29,12 @@ import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
|||
import org.mitre.oauth2.model.OAuth2RefreshTokenEntity;
|
||||
import org.mitre.oauth2.service.IntrospectionResultAssembler;
|
||||
import org.mitre.openid.connect.model.UserInfo;
|
||||
import org.mitre.uma.model.Permission;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Request;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import static com.google.common.collect.Sets.newHashSet;
|
||||
|
||||
|
@ -56,13 +58,15 @@ public class TestDefaultIntrospectionResultAssembler {
|
|||
public void shouldAssembleExpectedResultForAccessToken() throws ParseException {
|
||||
|
||||
// given
|
||||
OAuth2AccessTokenEntity accessToken = accessToken(new Date(123 * 1000L), scopes("foo", "bar"), "Bearer",
|
||||
OAuth2AccessTokenEntity accessToken = accessToken(new Date(123 * 1000L), scopes("foo", "bar"), null, "Bearer",
|
||||
authentication("name", request("clientId")));
|
||||
|
||||
UserInfo userInfo = userInfo("sub");
|
||||
|
||||
Set<String> authScopes = scopes("foo", "bar", "baz");
|
||||
|
||||
// when
|
||||
Map<String, Object> result = assembler.assembleFrom(accessToken, userInfo);
|
||||
Map<String, Object> result = assembler.assembleFrom(accessToken, userInfo, authScopes);
|
||||
|
||||
|
||||
// then
|
||||
|
@ -79,15 +83,56 @@ public class TestDefaultIntrospectionResultAssembler {
|
|||
assertThat(result, is(equalTo(expected)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldAssembleExpectedResultForAccessToken_withPermissions() throws ParseException {
|
||||
|
||||
// given
|
||||
OAuth2AccessTokenEntity accessToken = accessToken(new Date(123 * 1000L), scopes("foo", "bar"),
|
||||
permissions(permission(1L, "foo", "bar")),
|
||||
"Bearer", authentication("name", request("clientId")));
|
||||
|
||||
UserInfo userInfo = userInfo("sub");
|
||||
|
||||
Set<String> authScopes = scopes("foo", "bar", "baz");
|
||||
|
||||
// when
|
||||
Map<String, Object> result = assembler.assembleFrom(accessToken, userInfo, authScopes);
|
||||
|
||||
|
||||
// then
|
||||
Map<String, Object> expected = new ImmutableMap.Builder<String, Object>()
|
||||
.put("sub", "sub")
|
||||
.put("exp", 123L)
|
||||
.put("expires_at", dateFormat.valueToString(new Date(123 * 1000L)))
|
||||
.put("permissions", new ImmutableSet.Builder<Object>()
|
||||
.add(new ImmutableMap.Builder<String, Object>()
|
||||
.put("resource_set_id", "1") // note that the resource ID comes out as a string
|
||||
.put("scopes", new ImmutableSet.Builder<>()
|
||||
.add("bar")
|
||||
.add("foo")
|
||||
.build())
|
||||
.build())
|
||||
.build())
|
||||
// note that scopes are not included if permissions are included
|
||||
.put("active", Boolean.TRUE)
|
||||
.put("user_id", "name")
|
||||
.put("client_id", "clientId")
|
||||
.put("token_type", "Bearer")
|
||||
.build();
|
||||
assertThat(result, is(equalTo(expected)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldAssembleExpectedResultForAccessTokenWithoutUserInfo() throws ParseException {
|
||||
|
||||
// given
|
||||
OAuth2AccessTokenEntity accessToken = accessToken(new Date(123 * 1000L), scopes("foo", "bar"), "Bearer",
|
||||
OAuth2AccessTokenEntity accessToken = accessToken(new Date(123 * 1000L), scopes("foo", "bar"), null, "Bearer",
|
||||
authentication("name", request("clientId")));
|
||||
|
||||
Set<String> authScopes = scopes("foo", "bar", "baz");
|
||||
|
||||
// when
|
||||
Map<String, Object> result = assembler.assembleFrom(accessToken, null);
|
||||
Map<String, Object> result = assembler.assembleFrom(accessToken, null, authScopes);
|
||||
|
||||
|
||||
// then
|
||||
|
@ -108,13 +153,15 @@ public class TestDefaultIntrospectionResultAssembler {
|
|||
public void shouldAssembleExpectedResultForAccessTokenWithoutExpiry() {
|
||||
|
||||
// given
|
||||
OAuth2AccessTokenEntity accessToken = accessToken(null, scopes("foo", "bar"), "Bearer",
|
||||
OAuth2AccessTokenEntity accessToken = accessToken(null, scopes("foo", "bar"), null, "Bearer",
|
||||
authentication("name", request("clientId")));
|
||||
|
||||
UserInfo userInfo = userInfo("sub");
|
||||
|
||||
Set<String> authScopes = scopes("foo", "bar", "baz");
|
||||
|
||||
// when
|
||||
Map<String, Object> result = assembler.assembleFrom(accessToken, userInfo);
|
||||
Map<String, Object> result = assembler.assembleFrom(accessToken, userInfo, authScopes);
|
||||
|
||||
|
||||
// then
|
||||
|
@ -138,8 +185,10 @@ public class TestDefaultIntrospectionResultAssembler {
|
|||
|
||||
UserInfo userInfo = userInfo("sub");
|
||||
|
||||
Set<String> authScopes = scopes("foo", "bar", "baz");
|
||||
|
||||
// when
|
||||
Map<String, Object> result = assembler.assembleFrom(refreshToken, userInfo);
|
||||
Map<String, Object> result = assembler.assembleFrom(refreshToken, userInfo, authScopes);
|
||||
|
||||
|
||||
// then
|
||||
|
@ -162,8 +211,10 @@ public class TestDefaultIntrospectionResultAssembler {
|
|||
OAuth2RefreshTokenEntity refreshToken = refreshToken(new Date(123 * 1000L),
|
||||
authentication("name", request("clientId", scopes("foo", "bar"))));
|
||||
|
||||
Set<String> authScopes = scopes("foo", "bar", "baz");
|
||||
|
||||
// when
|
||||
Map<String, Object> result = assembler.assembleFrom(refreshToken, null);
|
||||
Map<String, Object> result = assembler.assembleFrom(refreshToken, null, authScopes);
|
||||
|
||||
|
||||
// then
|
||||
|
@ -188,8 +239,10 @@ public class TestDefaultIntrospectionResultAssembler {
|
|||
|
||||
UserInfo userInfo = userInfo("sub");
|
||||
|
||||
Set<String> authScopes = scopes("foo", "bar", "baz");
|
||||
|
||||
// when
|
||||
Map<String, Object> result = assembler.assembleFrom(refreshToken, userInfo);
|
||||
Map<String, Object> result = assembler.assembleFrom(refreshToken, userInfo, authScopes);
|
||||
|
||||
|
||||
// then
|
||||
|
@ -209,10 +262,11 @@ public class TestDefaultIntrospectionResultAssembler {
|
|||
return userInfo;
|
||||
}
|
||||
|
||||
private OAuth2AccessTokenEntity accessToken(Date exp, Set<String> scopes, String tokenType, OAuth2Authentication authentication) {
|
||||
private OAuth2AccessTokenEntity accessToken(Date exp, Set<String> scopes, Set<Permission> permissions, String tokenType, OAuth2Authentication authentication) {
|
||||
OAuth2AccessTokenEntity accessToken = mock(OAuth2AccessTokenEntity.class, RETURNS_DEEP_STUBS);
|
||||
given(accessToken.getExpiration()).willReturn(exp);
|
||||
given(accessToken.getScope()).willReturn(scopes);
|
||||
given(accessToken.getPermissions()).willReturn(permissions);
|
||||
given(accessToken.getTokenType()).willReturn(tokenType);
|
||||
given(accessToken.getAuthenticationHolder().getAuthentication()).willReturn(authentication);
|
||||
return accessToken;
|
||||
|
@ -243,4 +297,15 @@ public class TestDefaultIntrospectionResultAssembler {
|
|||
private Set<String> scopes(String... scopes) {
|
||||
return newHashSet(scopes);
|
||||
}
|
||||
|
||||
private Set<Permission> permissions(Permission... permissions) {
|
||||
return newHashSet(permissions);
|
||||
}
|
||||
|
||||
private Permission permission(Long resourceSetId, String... scopes) {
|
||||
Permission permission = mock(Permission.class, RETURNS_DEEP_STUBS);
|
||||
given(permission.getResourceSet().getId()).willReturn(resourceSetId);
|
||||
given(permission.getScopes()).willReturn(scopes(scopes));
|
||||
return permission;
|
||||
}
|
||||
}
|
||||
|
|
46
pom.xml
46
pom.xml
|
@ -41,6 +41,8 @@
|
|||
<module>openid-connect-client</module>
|
||||
<module>openid-connect-server</module>
|
||||
<module>openid-connect-server-webapp</module>
|
||||
<module>uma-server</module>
|
||||
<module>uma-server-webapp</module>
|
||||
</modules>
|
||||
|
||||
<scm>
|
||||
|
@ -54,12 +56,7 @@
|
|||
<developer>
|
||||
<id>jricher</id>
|
||||
<name>Justin Richer</name>
|
||||
<email>jricher@mitre.org</email>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>aanganes</id>
|
||||
<name>Amanda Anganes</name>
|
||||
<email>aanganes@mitre.org</email>
|
||||
<email>jricher@mit.edu</email>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
|
@ -77,7 +74,7 @@
|
|||
<spring.security.version>3.2.5.RELEASE</spring.security.version>
|
||||
<org.slf4j-version>1.7.7</org.slf4j-version>
|
||||
</properties>
|
||||
<description>A reference implementation of OpenID Connect (http://openid.net/connect/) and OAuth 2.0 built on top of Java, Spring, and Spring Security. The project contains a fully functioning server, client, and utility library.</description>
|
||||
<description>A reference implementation of OpenID Connect (http://openid.net/connect/), OAuth 2.0, and UMA built on top of Java, Spring, and Spring Security. The project contains a fully functioning server, client, and utility library.</description>
|
||||
<url>https://github.com/mitreid-connect</url>
|
||||
<build>
|
||||
<pluginManagement>
|
||||
|
@ -128,6 +125,11 @@
|
|||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.appfuse.plugins</groupId>
|
||||
<artifactId>warpath-maven-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<plugins>
|
||||
|
@ -185,7 +187,7 @@
|
|||
<configuration>
|
||||
<rules>
|
||||
<requireMavenVersion>
|
||||
<version>3.0.2</version>
|
||||
<version>3.1.0</version>
|
||||
</requireMavenVersion>
|
||||
</rules>
|
||||
<fail>true</fail>
|
||||
|
@ -452,11 +454,39 @@
|
|||
<artifactId>openid-connect-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mitre</groupId>
|
||||
<artifactId>openid-connect-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mitre</groupId>
|
||||
<artifactId>openid-connect-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mitre</groupId>
|
||||
<artifactId>openid-connect-server-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>war</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mitre</groupId>
|
||||
<artifactId>openid-connect-server-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>warpath</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mitre</groupId>
|
||||
<artifactId>uma-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mitre</groupId>
|
||||
<artifactId>uma-server-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>war</type>
|
||||
</dependency>
|
||||
|
||||
<!-- Other libraries -->
|
||||
<dependency>
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2015 The MITRE Corporation
|
||||
and the MIT Kerberos and 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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.mitre</groupId>
|
||||
<artifactId>openid-connect-parent</artifactId>
|
||||
<version>1.2.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>uma-server-webapp</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<name>UMA Server Webapp</name>
|
||||
<description>Deployable package of the User Managed Access (UMA) server extension to MITREid Connect</description>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.appfuse.plugins</groupId>
|
||||
<artifactId>warpath-maven-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>add-classes</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<configuration>
|
||||
<overlays>
|
||||
<overlay>
|
||||
<groupId>org.mitre</groupId>
|
||||
<artifactId>openid-connect-server-webapp</artifactId>
|
||||
</overlay>
|
||||
</overlays>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.mitre</groupId>
|
||||
<artifactId>openid-connect-server-webapp</artifactId>
|
||||
<type>war</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mitre</groupId>
|
||||
<artifactId>openid-connect-server-webapp</artifactId>
|
||||
<type>warpath</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mitre</groupId>
|
||||
<artifactId>uma-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mitre</groupId>
|
||||
<artifactId>openid-connect-client</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,77 @@
|
|||
--
|
||||
-- Turn off autocommit and start a transaction so that we can use the temp tables
|
||||
--
|
||||
|
||||
SET AUTOCOMMIT FALSE;
|
||||
|
||||
START TRANSACTION;
|
||||
|
||||
--
|
||||
-- Insert client information into the temporary tables. To add clients to the HSQL database, edit things here.
|
||||
--
|
||||
|
||||
INSERT INTO client_details_TEMP (client_id, client_secret, client_name, dynamically_registered, refresh_token_validity_seconds, access_token_validity_seconds, id_token_validity_seconds, allow_introspection) VALUES
|
||||
('client', 'secret', 'Test Client', false, null, 3600, 600, true),
|
||||
('rs', 'secret', 'Test UMA RS', false, null, null, 600, false),
|
||||
('c', 'secret', 'Test UMA Client', false, null, null, 600, false);
|
||||
|
||||
INSERT INTO client_scope_TEMP (owner_id, scope) VALUES
|
||||
('client', 'openid'),
|
||||
('client', 'profile'),
|
||||
('client', 'email'),
|
||||
('client', 'address'),
|
||||
('client', 'phone'),
|
||||
('client', 'offline_access'),
|
||||
('rs', 'uma_protection'),
|
||||
('c', 'uma_authorization');
|
||||
|
||||
INSERT INTO client_redirect_uri_TEMP (owner_id, redirect_uri) VALUES
|
||||
('client', 'http://localhost/'),
|
||||
('client', 'http://localhost:8080/');
|
||||
|
||||
INSERT INTO client_grant_type_TEMP (owner_id, grant_type) VALUES
|
||||
('client', 'authorization_code'),
|
||||
('client', 'urn:ietf:params:oauth:grant_type:redelegate'),
|
||||
('client', 'implicit'),
|
||||
('client', 'refresh_token'),
|
||||
('rs', 'authorization_code'),
|
||||
('rs', 'implicit'),
|
||||
('c', 'authorization_code'),
|
||||
('c', 'implicit');
|
||||
|
||||
--
|
||||
-- Merge the temporary clients safely into the database. This is a two-step process to keep clients from being created on every startup with a persistent store.
|
||||
--
|
||||
|
||||
MERGE INTO client_details
|
||||
USING (SELECT client_id, client_secret, client_name, dynamically_registered, refresh_token_validity_seconds, access_token_validity_seconds, id_token_validity_seconds, allow_introspection FROM client_details_TEMP) AS vals(client_id, client_secret, client_name, dynamically_registered, refresh_token_validity_seconds, access_token_validity_seconds, id_token_validity_seconds, allow_introspection)
|
||||
ON vals.client_id = client_details.client_id
|
||||
WHEN NOT MATCHED THEN
|
||||
INSERT (client_id, client_secret, client_name, dynamically_registered, refresh_token_validity_seconds, access_token_validity_seconds, id_token_validity_seconds, allow_introspection) VALUES(client_id, client_secret, client_name, dynamically_registered, refresh_token_validity_seconds, access_token_validity_seconds, id_token_validity_seconds, allow_introspection);
|
||||
|
||||
MERGE INTO client_scope
|
||||
USING (SELECT id, scope FROM client_scope_TEMP, client_details WHERE client_details.client_id = client_scope_TEMP.owner_id) AS vals(id, scope)
|
||||
ON vals.id = client_scope.owner_id AND vals.scope = client_scope.scope
|
||||
WHEN NOT MATCHED THEN
|
||||
INSERT (owner_id, scope) values (vals.id, vals.scope);
|
||||
|
||||
MERGE INTO client_redirect_uri
|
||||
USING (SELECT id, redirect_uri FROM client_redirect_uri_TEMP, client_details WHERE client_details.client_id = client_redirect_uri_TEMP.owner_id) AS vals(id, redirect_uri)
|
||||
ON vals.id = client_redirect_uri.owner_id AND vals.redirect_uri = client_redirect_uri.redirect_uri
|
||||
WHEN NOT MATCHED THEN
|
||||
INSERT (owner_id, redirect_uri) values (vals.id, vals.redirect_uri);
|
||||
|
||||
MERGE INTO client_grant_type
|
||||
USING (SELECT id, grant_type FROM client_grant_type_TEMP, client_details WHERE client_details.client_id = client_grant_type_TEMP.owner_id) AS vals(id, grant_type)
|
||||
ON vals.id = client_grant_type.owner_id AND vals.grant_type = client_grant_type.grant_type
|
||||
WHEN NOT MATCHED THEN
|
||||
INSERT (owner_id, grant_type) values (vals.id, vals.grant_type);
|
||||
|
||||
--
|
||||
-- Close the transaction and turn autocommit back on
|
||||
--
|
||||
|
||||
COMMIT;
|
||||
|
||||
SET AUTOCOMMIT TRUE;
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
--
|
||||
-- Turn off autocommit and start a transaction so that we can use the temp tables
|
||||
--
|
||||
|
||||
SET AUTOCOMMIT FALSE;
|
||||
|
||||
START TRANSACTION;
|
||||
|
||||
--
|
||||
-- Insert scope information into the temporary tables.
|
||||
--
|
||||
|
||||
INSERT INTO system_scope_TEMP (scope, description, icon, restricted, default_scope, structured, structured_param_description) VALUES
|
||||
('openid', 'log in using your identity', 'user', false, true, false, null),
|
||||
('profile', 'basic profile information', 'list-alt', false, true, false, null),
|
||||
('email', 'email address', 'envelope', false, true, false, null),
|
||||
('address', 'physical address', 'home', false, true, false, null),
|
||||
('phone', 'telephone number', 'bell', false, true, false, null),
|
||||
('offline_access', 'offline access', 'time', false, false, false, null),
|
||||
('uma_protection', 'manage protected resources', 'briefcase', false, false, false, null),
|
||||
('uma_authorization', 'request access to protected resources', 'share', false, false, false, null);
|
||||
|
||||
--
|
||||
-- Merge the temporary scopes safely into the database. This is a two-step process to keep scopes from being created on every startup with a persistent store.
|
||||
--
|
||||
|
||||
MERGE INTO system_scope
|
||||
USING (SELECT scope, description, icon, restricted, default_scope, structured, structured_param_description FROM system_scope_TEMP) AS vals(scope, description, icon, restricted, default_scope, structured, structured_param_description)
|
||||
ON vals.scope = system_scope.scope
|
||||
WHEN NOT MATCHED THEN
|
||||
INSERT (scope, description, icon, restricted, default_scope, structured, structured_param_description) VALUES(vals.scope, vals.description, vals.icon, vals.restricted, vals.default_scope, vals.structured, vals.structured_param_description);
|
||||
|
||||
COMMIT;
|
||||
|
||||
SET AUTOCOMMIT TRUE;
|
|
@ -0,0 +1,267 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2015 The MITRE Corporation
|
||||
and the MIT Kerberos and 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.
|
||||
-->
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:mvc="http://www.springframework.org/schema/mvc"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:security="http://www.springframework.org/schema/security"
|
||||
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
|
||||
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
|
||||
|
||||
<!-- Scan for components -->
|
||||
<context:component-scan annotation-config="true" base-package="org.mitre" />
|
||||
|
||||
<!-- Enables the Spring MVC @Controller programming model -->
|
||||
<tx:annotation-driven transaction-manager="transactionManager" />
|
||||
<mvc:annotation-driven ignore-default-model-on-redirect="true">
|
||||
<mvc:message-converters>
|
||||
<bean class="org.springframework.http.converter.StringHttpMessageConverter" />
|
||||
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
|
||||
</mvc:message-converters>
|
||||
</mvc:annotation-driven>
|
||||
|
||||
<mvc:interceptors>
|
||||
<!-- Inject the UserInfo into the response -->
|
||||
<bean id="userInfoInterceptor" class="org.mitre.openid.connect.web.UserInfoInterceptor" />
|
||||
<!-- Inject the server configuration into the response -->
|
||||
<bean id="serverConfigInterceptor" class="org.mitre.openid.connect.web.ServerConfigInterceptor" />
|
||||
</mvc:interceptors>
|
||||
|
||||
<mvc:default-servlet-handler />
|
||||
|
||||
<!-- Bean to hold configuration properties -->
|
||||
<import resource="server-config.xml" />
|
||||
|
||||
<!-- Import the data context -->
|
||||
<import resource="data-context.xml" />
|
||||
|
||||
<!-- SPEL processors -->
|
||||
<security:global-method-security pre-post-annotations="enabled" proxy-target-class="true" authentication-manager-ref="authenticationManager">
|
||||
<!--you could also wire in the expression handler up at the layer of the http filters. See https://jira.springsource.org/browse/SEC-1452 -->
|
||||
<security:expression-handler ref="oauthExpressionHandler" />
|
||||
</security:global-method-security>
|
||||
|
||||
<oauth:expression-handler id="oauthExpressionHandler" />
|
||||
|
||||
<oauth:web-expression-handler id="oauthWebExpressionHandler" />
|
||||
|
||||
<!-- Spring Security configuration -->
|
||||
|
||||
<oauth:resource-server id="resourceServerFilter" token-services-ref="defaultOAuth2ProviderTokenService" />
|
||||
|
||||
<security:http pattern="/token"
|
||||
create-session="stateless"
|
||||
authentication-manager-ref="clientAuthenticationManager"
|
||||
entry-point-ref="oauthAuthenticationEntryPoint"
|
||||
use-expressions="true">
|
||||
|
||||
<security:intercept-url pattern="/token" access="permitAll" method="OPTIONS" /> <!-- allow OPTIONS calls without auth for CORS stuff -->
|
||||
<security:intercept-url pattern="/token" access="isAuthenticated()" />
|
||||
<security:http-basic entry-point-ref="oauthAuthenticationEntryPoint" />
|
||||
<!-- include this only if you need to authenticate clients via request parameters -->
|
||||
<security:custom-filter ref="clientAssertionEndpointFilter" after="PRE_AUTH_FILTER" /> <!-- this one has to go first -->
|
||||
<security:custom-filter ref="clientCredentialsEndpointFilter" after="BASIC_AUTH_FILTER" />
|
||||
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
|
||||
<security:access-denied-handler ref="oauthAccessDeniedHandler" />
|
||||
</security:http>
|
||||
|
||||
<!-- Allow open access to discovery endpoints -->
|
||||
<security:http pattern="/#{T(org.mitre.openid.connect.web.JWKSetPublishingEndpoint).URL}**" use-expressions="true" entry-point-ref="http403EntryPoint" create-session="stateless">
|
||||
<security:intercept-url pattern="/#{T(org.mitre.openid.connect.web.JWKSetPublishingEndpoint).URL}**" access="permitAll"/>
|
||||
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
|
||||
</security:http>
|
||||
<security:http pattern="/#{T(org.mitre.discovery.web.DiscoveryEndpoint).WELL_KNOWN_URL}/**" use-expressions="true" entry-point-ref="http403EntryPoint" create-session="stateless">
|
||||
<security:intercept-url pattern="/#{T(org.mitre.discovery.web.DiscoveryEndpoint).WELL_KNOWN_URL}/**" access="permitAll"/>
|
||||
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
|
||||
</security:http>
|
||||
|
||||
<!-- Allow open access to all static resources -->
|
||||
<security:http pattern="/resources/**" use-expressions="true" entry-point-ref="http403EntryPoint" create-session="stateless">
|
||||
<security:intercept-url pattern="/resources/**" access="permitAll"/>
|
||||
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
|
||||
</security:http>
|
||||
|
||||
<!-- OAuth-protect API and other endpoints -->
|
||||
<security:http pattern="/#{T(org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint).URL}/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="stateless">
|
||||
<security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
|
||||
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
|
||||
<security:expression-handler ref="oauthWebExpressionHandler" />
|
||||
<security:intercept-url pattern="/register/**" access="permitAll"/>
|
||||
</security:http>
|
||||
|
||||
<security:http pattern="/#{T(org.mitre.openid.connect.web.ProtectedResourceRegistrationEndpoint).URL}/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="stateless">
|
||||
<security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
|
||||
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
|
||||
<security:expression-handler ref="oauthWebExpressionHandler" />
|
||||
<security:intercept-url pattern="/resource/**" access="permitAll"/>
|
||||
</security:http>
|
||||
|
||||
<security:http pattern="/#{T(org.mitre.uma.web.ResourceSetRegistrationEndpoint).URL}/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="never">
|
||||
<security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
|
||||
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
|
||||
<security:expression-handler ref="oauthWebExpressionHandler" />
|
||||
</security:http>
|
||||
|
||||
<security:http pattern="/#{T(org.mitre.uma.web.PermissionRegistrationEndpoint).URL}/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="never">
|
||||
<security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
|
||||
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
|
||||
<security:expression-handler ref="oauthWebExpressionHandler" />
|
||||
</security:http>
|
||||
|
||||
<security:http pattern="/#{T(org.mitre.uma.web.AuthorizationRequestEndpoint).URL}/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="never">
|
||||
<security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
|
||||
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
|
||||
<security:expression-handler ref="oauthWebExpressionHandler" />
|
||||
</security:http>
|
||||
|
||||
<security:http pattern="/#{T(org.mitre.openid.connect.web.UserInfoEndpoint).URL}**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="stateless">
|
||||
<security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
|
||||
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
|
||||
<security:expression-handler ref="oauthWebExpressionHandler" />
|
||||
</security:http>
|
||||
|
||||
<security:http pattern="/#{T(org.mitre.openid.connect.web.RootController).API_URL}/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="never">
|
||||
<security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
|
||||
<security:expression-handler ref="oauthWebExpressionHandler" />
|
||||
</security:http>
|
||||
|
||||
<security:http pattern="/#{T(org.mitre.oauth2.web.IntrospectionEndpoint).URL}**"
|
||||
use-expressions="true"
|
||||
entry-point-ref="oauthAuthenticationEntryPoint"
|
||||
create-session="stateless"
|
||||
authentication-manager-ref="clientAuthenticationManager">
|
||||
<security:http-basic entry-point-ref="oauthAuthenticationEntryPoint" />
|
||||
<security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
|
||||
<security:custom-filter ref="clientAssertionEndpointFilter" after="PRE_AUTH_FILTER" /> <!-- this one has to go first -->
|
||||
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
|
||||
<security:custom-filter ref="clientCredentialsEndpointFilter" after="BASIC_AUTH_FILTER" />
|
||||
</security:http>
|
||||
|
||||
<security:http pattern="/#{T(org.mitre.oauth2.web.RevocationEndpoint).URL}**"
|
||||
use-expressions="true"
|
||||
entry-point-ref="oauthAuthenticationEntryPoint"
|
||||
create-session="stateless"
|
||||
authentication-manager-ref="clientAuthenticationManager">
|
||||
<security:http-basic entry-point-ref="oauthAuthenticationEntryPoint" />
|
||||
<!-- <security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" /> -->
|
||||
<security:custom-filter ref="clientAssertionEndpointFilter" after="PRE_AUTH_FILTER" /> <!-- this one has to go first -->
|
||||
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
|
||||
<security:custom-filter ref="clientCredentialsEndpointFilter" after="BASIC_AUTH_FILTER" />
|
||||
</security:http>
|
||||
|
||||
<bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
|
||||
<property name="realmName" value="openidconnect" />
|
||||
</bean>
|
||||
|
||||
<bean id="http403EntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint" />
|
||||
|
||||
<!-- SECOAUTH Authorization Server -->
|
||||
|
||||
<import resource="authz-config.xml" />
|
||||
|
||||
<bean id="oauth2ExceptionTranslator" class="org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator" />
|
||||
|
||||
<bean id="clientAuthMatcher" class="org.mitre.openid.connect.filter.MultiUrlRequestMatcher">
|
||||
<constructor-arg name="filterProcessesUrls">
|
||||
<set>
|
||||
<value>/introspect</value>
|
||||
<value>/revoke</value>
|
||||
<value>/token</value>
|
||||
</set>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="clientCredentialsEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
|
||||
<property name="authenticationManager" ref="clientAuthenticationManager" />
|
||||
<property name="requiresAuthenticationRequestMatcher" ref="clientAuthMatcher" />
|
||||
</bean>
|
||||
|
||||
<bean id="clientAssertionEndpointFilter" class="org.mitre.openid.connect.assertion.JWTBearerClientAssertionTokenEndpointFilter">
|
||||
<constructor-arg name="additionalMatcher" ref="clientAuthMatcher" />
|
||||
<property name="authenticationManager" ref="clientAssertionAuthenticationManager" />
|
||||
</bean>
|
||||
|
||||
<security:authentication-manager id="clientAuthenticationManager">
|
||||
<security:authentication-provider user-service-ref="clientUserDetailsService" />
|
||||
</security:authentication-manager>
|
||||
|
||||
<security:authentication-manager id="clientAssertionAuthenticationManager">
|
||||
<security:authentication-provider ref="clientAssertionAuthenticationProvider" />
|
||||
</security:authentication-manager>
|
||||
|
||||
<bean id="clientAssertionAuthenticationProvider" class="org.mitre.openid.connect.assertion.JWTBearerAuthenticationProvider" />
|
||||
|
||||
<!-- Configure locale information -->
|
||||
<bean id="messageSource" class="org.mitre.openid.connect.config.JsonMessageSource">
|
||||
<property name="baseDirectory" value="/resources/js/locale/" />
|
||||
</bean>
|
||||
|
||||
<!-- user services -->
|
||||
<import resource="user-context.xml" />
|
||||
|
||||
<!-- End Spring Security configuration -->
|
||||
|
||||
<!-- JPA -->
|
||||
|
||||
<import resource="jpa-config.xml" />
|
||||
|
||||
<!-- End JPA -->
|
||||
|
||||
<!-- Crypto -->
|
||||
|
||||
<import resource="crypto-config.xml" />
|
||||
|
||||
<!-- End Crypto -->
|
||||
|
||||
<!-- View configuration -->
|
||||
|
||||
<!-- Handles HTTP GET requests for /resources/** by efficiently serving
|
||||
up static resources in the ${webappRoot}/resources directory -->
|
||||
<mvc:resources mapping="/resources/**" location="/resources/" />
|
||||
|
||||
<!-- Resolves views selected for rendering by @Controllers to .jsp resources
|
||||
in the /WEB-INF/views directory -->
|
||||
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
|
||||
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
|
||||
<property name="prefix" value="/WEB-INF/views/" />
|
||||
<property name="suffix" value=".jsp" />
|
||||
<property name="order" value="2" />
|
||||
</bean>
|
||||
|
||||
<!-- Resolve views based on string names -->
|
||||
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
|
||||
<property name="order" value="1" />
|
||||
</bean>
|
||||
|
||||
<!-- End view configuration -->
|
||||
|
||||
<!--Import scheduled task configuration -->
|
||||
<import resource="task-config.xml" />
|
||||
|
||||
<!-- import application-local configuration information (such as bean definitions) -->
|
||||
<import resource="local-config.xml" />
|
||||
|
||||
</beans>
|
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2015 The MITRE Corporation
|
||||
and the MIT Kerberos and 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.
|
||||
-->
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:mvc="http://www.springframework.org/schema/mvc"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:security="http://www.springframework.org/schema/security"
|
||||
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
|
||||
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
|
||||
|
||||
<bean id="configBean" class="org.mitre.openid.connect.config.ConfigurationPropertiesBean">
|
||||
|
||||
<!-- This property sets the root URL of the server, known as the issuer -->
|
||||
<property name="issuer" value="http://localhost:8080/uma-server-webapp/" />
|
||||
|
||||
<!-- This property is a URL pointing to a logo image 24px high to be used in the top bar -->
|
||||
<property name="logoImageUrl" value="resources/images/openid_connect_small.png" />
|
||||
|
||||
<!-- This property sets the display name of the server, displayed in the topbar and page title -->
|
||||
<property name="topbarTitle" value="UMA Server" />
|
||||
|
||||
<!-- This property sets the lifetime of registration access tokens, in seconds. Leave it unset (null) for no rotation. -->
|
||||
<!-- <property name="regTokenLifeTime" value="172800" /> -->
|
||||
|
||||
<!-- This property forces the issuer value to start with "https" -->
|
||||
<!-- <property name="forceHttps" value="true" /> -->
|
||||
|
||||
<!-- This property sets the locale for server text -->
|
||||
<!-- <property name="locale" value="sv" /> -->
|
||||
|
||||
</bean>
|
||||
|
||||
</beans>
|
|
@ -0,0 +1,21 @@
|
|||
<%@ tag language="java" pageEncoding="UTF-8"%>
|
||||
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
|
||||
<%@ taglib prefix="security"
|
||||
uri="http://www.springframework.org/security/tags"%>
|
||||
<security:authorize access="hasRole('ROLE_ADMIN')">
|
||||
<li class="nav-header"><spring:message code="sidebar.administrative.title"/></li>
|
||||
<li><a href="manage/#admin/clients" data-toggle="collapse" data-target=".nav-collapse"><spring:message code="sidebar.administrative.manage_clients"/></a></li>
|
||||
<li><a href="manage/#admin/whitelists" data-toggle="collapse" data-target=".nav-collapse"><spring:message code="sidebar.administrative.whitelisted_clients"/></a></li>
|
||||
<li><a href="manage/#admin/blacklist" data-toggle="collapse" data-target=".nav-collapse"><spring:message code="sidebar.administrative.blacklisted_clients"/></a></li>
|
||||
<li><a href="manage/#admin/scope" data-toggle="collapse" data-target=".nav-collapse"><spring:message code="sidebar.administrative.system_scopes"/></a></li>
|
||||
<li class="divider"></li>
|
||||
</security:authorize>
|
||||
<li class="nav-header"><spring:message code="sidebar.personal.title"/></li>
|
||||
<li><a href="manage/#user/approved" data-toggle="collapse" data-target=".nav-collapse"><spring:message code="sidebar.personal.approved_sites"/></a></li>
|
||||
<li><a href="manage/#user/tokens" data-toggle="collapse" data-target=".nav-collapse"><spring:message code="sidebar.personal.active_tokens"/></a></li>
|
||||
<li><a href="manage/#user/profile" data-toggle="collapse" data-target=".nav-collapse"><spring:message code="sidebar.personal.profile_information"/></a></li>
|
||||
<li><a href="manage/#user/policy" data-toggle="collapse" data-target=".nav-collapse"><spring:message code="sidebar.personal.resource_policies"/></a></li>
|
||||
<li class="divider"></li>
|
||||
<li class="nav-header"><spring:message code="sidebar.developer.title"/></li>
|
||||
<li><a href="manage/#dev/dynreg" data-toggle="collapse" data-target=".nav-collapse"><spring:message code="sidebar.developer.client_registration"/></a><li>
|
||||
<li><a href="manage/#dev/resource" data-toggle="collapse" data-target=".nav-collapse"><spring:message code="sidebar.developer.resource_registration"/></a><li>
|
|
@ -0,0 +1,38 @@
|
|||
<%@ attribute name="js" required="false"%>
|
||||
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
||||
<%@ taglib prefix="o" tagdir="/WEB-INF/tags"%>
|
||||
<div id="push"></div>
|
||||
</div>
|
||||
<!-- end #wrap -->
|
||||
<div id="footer">
|
||||
<div class="container">
|
||||
<p class="muted credit">
|
||||
<o:copyright />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- javascript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script type="text/javascript" src="resources/bootstrap2/js/bootstrap.js"></script>
|
||||
<script type="text/javascript" src="resources/js/lib/underscore.js"></script>
|
||||
<script type="text/javascript" src="resources/js/lib/backbone.js"></script>
|
||||
<script type="text/javascript" src="resources/js/lib/purl.js"></script>
|
||||
<script type="text/javascript" src="resources/js/lib/bootstrapx-clickover.js"></script>
|
||||
<script type="text/javascript" src="resources/js/lib/bootstrap-sheet.js"></script>
|
||||
<script type="text/javascript" src="resources/js/lib/bootpag.js"></script>
|
||||
<c:if test="${js != null && js != ''}">
|
||||
<script type="text/javascript" src="resources/js/client.js"></script>
|
||||
<script type="text/javascript" src="resources/js/grant.js"></script>
|
||||
<script type="text/javascript" src="resources/js/scope.js"></script>
|
||||
<script type="text/javascript" src="resources/js/whitelist.js"></script>
|
||||
<script type="text/javascript" src="resources/js/dynreg.js"></script>
|
||||
<script type="text/javascript" src="resources/js/rsreg.js"></script>
|
||||
<script type="text/javascript" src="resources/js/token.js"></script>
|
||||
<script type="text/javascript" src="resources/js/policy.js"></script>
|
||||
<script type="text/javascript" src="resources/js/admin.js"></script>
|
||||
</c:if>
|
||||
<script type="text/javascript" src="resources/js/lib/retina.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,146 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2015 The MITRE Corporation
|
||||
and the MIT Kerberos and 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.
|
||||
-->
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:mvc="http://www.springframework.org/schema/mvc"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:security="http://www.springframework.org/schema/security"
|
||||
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
|
||||
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
|
||||
|
||||
|
||||
<!-- Support for external OIDC logins for claims gathering -->
|
||||
|
||||
<mvc:view-controller path="/external_login" view-name="external_login" />
|
||||
|
||||
<security:http pattern="/external_login**" use-expressions="true" entry-point-ref="http403EntryPoint">
|
||||
<security:intercept-url pattern="/external_login**" access="permitAll"/>
|
||||
</security:http>
|
||||
|
||||
<security:http disable-url-rewriting="true" use-expressions="true"
|
||||
auto-config="false" entry-point-ref="externalAuthenticationEntryPoint"
|
||||
pattern="/#{T(org.mitre.uma.web.ClaimsCollectionEndpoint).URL}**">
|
||||
|
||||
<security:logout logout-url="/logout" />
|
||||
<security:expression-handler ref="oauthWebExpressionHandler" />
|
||||
</security:http>
|
||||
|
||||
<bean id="externalAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
|
||||
<property name="loginFormUrl" value="/openid_connect_login" />
|
||||
</bean>
|
||||
|
||||
<security:authentication-manager id="externalAuthenticationManager">
|
||||
<security:authentication-provider ref="externalAuthenticationProvider" />
|
||||
</security:authentication-manager>
|
||||
|
||||
<bean id="externalAuthenticationProvider" class="org.mitre.openid.connect.client.OIDCAuthenticationProvider">
|
||||
<property name="authoritiesMapper">
|
||||
<bean class="org.mitre.uma.util.ExternalLoginAuthoritiesMapper" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="externalAuthenticationFilter" class="org.mitre.openid.connect.client.OIDCAuthenticationFilter">
|
||||
<property name="authenticationManager" ref="externalAuthenticationManager" />
|
||||
|
||||
<property name="issuerService" ref="hybridIssuerService" />
|
||||
<property name="serverConfigurationService" ref="dynamicServerConfigurationService" />
|
||||
<property name="clientConfigurationService" ref="dynamicClientConfigurationService" />
|
||||
<property name="authRequestOptionsService" ref="staticAuthRequestOptionsService" />
|
||||
<property name="authRequestUrlBuilder" ref="plainAuthRequestUrlBuilder" />
|
||||
|
||||
</bean>
|
||||
|
||||
<bean class="org.mitre.openid.connect.client.service.impl.HybridIssuerService" id="hybridIssuerService">
|
||||
<property name="loginPageUrl" value="external_login" />
|
||||
</bean>
|
||||
|
||||
<bean class="org.mitre.openid.connect.client.service.impl.DynamicServerConfigurationService" id="dynamicServerConfigurationService" />
|
||||
|
||||
<bean class="org.mitre.openid.connect.client.service.impl.DynamicRegistrationClientConfigurationService" id="dynamicClientConfigurationService">
|
||||
<property name="template">
|
||||
<bean class="org.mitre.oauth2.model.RegisteredClient">
|
||||
<property name="clientName" value="HealthAuth Authorization Server" />
|
||||
<property name="scope">
|
||||
<set value-type="java.lang.String">
|
||||
<value>openid</value>
|
||||
<value>profile</value>
|
||||
<value>email</value>
|
||||
<value>phone</value>
|
||||
<value>address</value>
|
||||
</set>
|
||||
</property>
|
||||
<property name="tokenEndpointAuthMethod" value="SECRET_BASIC" />
|
||||
<property name="redirectUris">
|
||||
<set>
|
||||
<value>#{configBean.issuer + "openid_connect_login"}</value>
|
||||
</set>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
<!--
|
||||
Registered Client Service. Uncomment this to save dynamically registered clients out to a
|
||||
file on disk (indicated by the filename property) or replace this with another implementation
|
||||
of RegisteredClientService. This defaults to an in-memory implementation of RegisteredClientService
|
||||
which will forget and re-register all clients on restart.
|
||||
-->
|
||||
<!--
|
||||
<property name="registeredClientService">
|
||||
<bean class="org.mitre.openid.connect.client.service.impl.JsonFileRegisteredClientService">
|
||||
<constructor-arg name="filename" value="/tmp/simple-web-app-clients.json" />
|
||||
</bean>
|
||||
</property>
|
||||
-->
|
||||
</bean>
|
||||
|
||||
<bean class="org.mitre.openid.connect.client.service.impl.StaticAuthRequestOptionsService" id="staticAuthRequestOptionsService" />
|
||||
|
||||
<bean class="org.mitre.openid.connect.client.service.impl.PlainAuthRequestUrlBuilder" id="plainAuthRequestUrlBuilder" />
|
||||
|
||||
|
||||
<!-- Standard configuration -->
|
||||
|
||||
<security:authentication-manager alias="authenticationManager">
|
||||
<security:authentication-provider>
|
||||
<security:jdbc-user-service data-source-ref="dataSource"/>
|
||||
</security:authentication-provider>
|
||||
</security:authentication-manager>
|
||||
|
||||
<mvc:view-controller path="/login" view-name="login" />
|
||||
|
||||
|
||||
<security:http pattern="/login**" use-expressions="true" entry-point-ref="http403EntryPoint">
|
||||
<security:intercept-url pattern="/login**" access="permitAll"/>
|
||||
</security:http>
|
||||
|
||||
<security:http disable-url-rewriting="true" use-expressions="true">
|
||||
<security:form-login login-page="/login" authentication-failure-url="/login?error=failure" authentication-success-handler-ref="authenticationTimeStamper" />
|
||||
<security:intercept-url pattern="/**" access="permitAll" />
|
||||
<security:custom-filter before="PRE_AUTH_FILTER" ref="externalAuthenticationFilter" />
|
||||
<security:custom-filter ref="authRequestFilter" after="SECURITY_CONTEXT_FILTER" />
|
||||
<security:logout logout-url="/logout" />
|
||||
<security:anonymous />
|
||||
<security:expression-handler ref="oauthWebExpressionHandler" />
|
||||
</security:http>
|
||||
|
||||
</beans>
|
|
@ -0,0 +1,42 @@
|
|||
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||||
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
|
||||
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
|
||||
<%@ taglib prefix="o" tagdir="/WEB-INF/tags"%>
|
||||
<o:header title="Login"/>
|
||||
<o:topbar />
|
||||
<div class="container-fluid main">
|
||||
<div class="row-fluid">
|
||||
<div class="span10 offset1">
|
||||
|
||||
<h2>Log In</h2>
|
||||
|
||||
<p>Enter your email address to log in</p>
|
||||
|
||||
<div class="well">
|
||||
<div class="row-fluid">
|
||||
|
||||
<div class="span8">
|
||||
<form action="openid_connect_login" method="get">
|
||||
<input type="text" class="input-xxlarge" name="identifier" id="identifier" />
|
||||
<input type="submit" value="Log In" />
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
$('#localhost').on('click', function() {
|
||||
$('#identifier').val('http://localhost:8080/openid-connect-server-webapp/');
|
||||
});
|
||||
$('#mitreidorg').on('click', function() {
|
||||
$('#identifier').val('user@mitreid.org');
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
<o:footer />
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,477 @@
|
|||
{
|
||||
"admin": {
|
||||
"blacklist": "Blacklist",
|
||||
"blacklist-form": {
|
||||
"blacklisted-uris": "Blacklisted URIs"
|
||||
},
|
||||
"home": "Home",
|
||||
"list-widget": {
|
||||
"empty": "There are no items in this list.",
|
||||
"tooltip": "Click to display full value."
|
||||
},
|
||||
"manage-blacklist": "Manage Blacklisted Clients",
|
||||
"self-service-client": "Self-service Client Registration",
|
||||
"self-service-resource": "Self-service Protected Resource Registration",
|
||||
"user-profile": {
|
||||
"claim": "Claim name:",
|
||||
"show": "View User Profile",
|
||||
"text": "Your user profile has the following information:",
|
||||
"value": "Claim value:"
|
||||
},
|
||||
"policies": "Manage Protected Resource Policies"
|
||||
},
|
||||
"client": {
|
||||
"client-form": {
|
||||
"access": "Access",
|
||||
"access-token-no-timeout": "Access tokens do not time out",
|
||||
"access-token-timeout": "Access Token Timeout",
|
||||
"access-token-timeout-help": "Enter this time in seconds, minutes, or hours.",
|
||||
"acr-values": "Default ACR Values",
|
||||
"acr-values-placeholder": "new ACR value",
|
||||
"acr-values-help": "Default Authentication Context Reference to request for this client",
|
||||
"allow-introspection": "Allow calls to the Introspection Endpoint?",
|
||||
"authentication-method": "Token Endpoint Authentication Method",
|
||||
"authorization-code": "authorization code",
|
||||
"client-credentials": "client credentials",
|
||||
"client-description": "Description",
|
||||
"client-description-help": "Human-readable text description",
|
||||
"client-description-placeholder": "Type a description",
|
||||
"client-id": "Client ID",
|
||||
"client-id-help": "Unique identifier. If you leave this blank it will be automatically generated.",
|
||||
"client-id-placeholder": "Type something",
|
||||
"client-name": "Client name",
|
||||
"client-name-help": "Human-readable application name",
|
||||
"client-name-placeholder": "Type something",
|
||||
"client-secret": "Client Secret",
|
||||
"client-secret-placeholder": "Type a secret",
|
||||
"contacts": "Contacts",
|
||||
"contacts-help": "List of contacts for administrators of this client.",
|
||||
"contacts-placeholder": "new contact",
|
||||
"credentials": "Credentials",
|
||||
"crypto": {
|
||||
"a128cbc-hs256": "Composite Authenticated Encryption algorithm using AES in Cipher Block Chaining (CBC) mode with PKCS #5 padding with an integrity calculation using HMAC SHA-256, using a 256 bit CMK (and 128 bit CEK)",
|
||||
"a256cbc-hs512": "Composite Authenticated Encryption algorithm using AES in CBC mode with PKCS #5 padding with an integrity calculation using HMAC SHA-512, using a 512 bit CMK (and 256 bit CEK)",
|
||||
"a128gcm": "AES GCM using 128 bit keys",
|
||||
"a256gcm": "AES GCM using 256 bit keys",
|
||||
"a128kw": "AES Key Wrap Algorithm using 128 bit keys",
|
||||
"a256kw": "AES Key Wrap Algorithm using 256 bit keys",
|
||||
"default": "Use server default",
|
||||
"dir": "Direct use of a shared symmetric key as the Content Master Key (CMK) for the block encryption step",
|
||||
"ecdh-es": "Elliptic Curve Diffie-Hellman Ephemeral Static key agreement using the Concat KDF, with the agreed-upon key being used directly as the Content Master Key",
|
||||
"ecdh-es-a128kw": "Elliptic Curve Diffie-Hellman Ephemeral Static key agreement per ECDH-ES and Section 4.7, but where the agreed-upon key is used to wrap the Content Master Key (CMK) with the A128KW function",
|
||||
"ecdh-es-a256kw": "Elliptic Curve Diffie-Hellman Ephemeral Static key agreement per ECDH-ES and Section 4.7, but where the agreed-upon key is used to wrap the Content Master Key (CMK) with the A256KW function",
|
||||
"none": "No encryption",
|
||||
"rsa-oaep": "RSAES using Optimal Asymmetric Encryption Padding (OAEP)",
|
||||
"rsa1-5": "RSAES-PKCS1-V1_5"
|
||||
},
|
||||
"cryptography": "Crypto",
|
||||
"display-secret": "Display/edit client secret:",
|
||||
"edit": "Edit Client",
|
||||
"generate-new-secret": "Generate a new client secret?",
|
||||
"generate-new-secret-help": "New secret will be generated when you click 'Save'",
|
||||
"generate-on-save": "Generate on Save",
|
||||
"grant-types": "Grant Types",
|
||||
"home": "Home Page",
|
||||
"home-help": "URL for the client's home page, will be displayed to the user",
|
||||
"hours": "hours",
|
||||
"id": "ID:",
|
||||
"id-token-crypto-algorithm": "ID Token Encryption Algorithm",
|
||||
"id-token-crypto-method": "ID Token Encryption Method",
|
||||
"id-token-signing-algorithm": "ID Token Signing Algorithm",
|
||||
"id-token-timeout": "ID Token Timeout",
|
||||
"implicit": "implicit",
|
||||
"initiate-login": "Initiate Login",
|
||||
"initiate-login-help": "URL to initiate login on the client",
|
||||
"introspection": "Introspection",
|
||||
"jwk-set": "JWK Set",
|
||||
"jwk-set-help": "URL for the client's JSON Web Key set",
|
||||
"logo": "Logo",
|
||||
"logo-help": "URL that points to a logo image, will be displayed on approval page",
|
||||
"main": "Main",
|
||||
"max-age": "Default Max Age",
|
||||
"max-age-help": "Default maximum session age before re-prompting",
|
||||
"minutes": "minutes",
|
||||
"new": "New Client",
|
||||
"other": "Other",
|
||||
"pairwise": "Pairwise",
|
||||
"password": "password",
|
||||
"policy": "Policy Statement",
|
||||
"policy-help": "URL for the Policy Statement of this client, will be displayed to the user",
|
||||
"post-logout": "Post-Logout Redirect",
|
||||
"post-logout-help": "URL to redirect the client to after a logout operation",
|
||||
"public": "Public",
|
||||
"redelegation": "redelegation",
|
||||
"redirect-uris": "Redirect URI(s)",
|
||||
"redirect-uris-help": "URIs that the client can be redirected to after the authorization page",
|
||||
"refresh": "refresh",
|
||||
"refresh-tokens": "Refresh Tokens",
|
||||
"refresh-tokens-issued": "Refresh tokens are issued for this client",
|
||||
"refresh-tokens-reused": "Refresh tokens for this client are re-used",
|
||||
"refresh-tokens-no-expire": "Refresh tokens do not time out",
|
||||
"registered": "Registered at",
|
||||
"registration-token": "Registration Token:",
|
||||
"registration-access-token": "Registration Access Token",
|
||||
"registration-token-error": "There was a problem loading the registration access token for this client.",
|
||||
"request-object-signing-algorithm": "Request Object Signing Algorithm",
|
||||
"request-uri": "Request URIs",
|
||||
"request-uri-help": "URIs containing request objects used by this client",
|
||||
"require-auth-time": "Require Authentication Time",
|
||||
"require-auth-time-label": "Always require that the auth_time claim be sent in the id token",
|
||||
"response-types": "Response Types",
|
||||
"rotate-registration-token": "Rotate registration token",
|
||||
"rotate-registration-token-confirm": "Are you sure you want to rotate this client's registration token?",
|
||||
"rotate-registration-token-error": "There was a problem rotating the registration access token for this client.",
|
||||
"saved": {
|
||||
"no-secret": "No client secret",
|
||||
"saved": "Client Saved",
|
||||
"secret": "Secret:",
|
||||
"show-secret": "Show Secret",
|
||||
"unchanged": "unchanged"
|
||||
},
|
||||
"scope-placeholder": "new scope",
|
||||
"scope-help": "OAuth scopes this client is allowed to request",
|
||||
"seconds": "seconds",
|
||||
"secret-asymmetric-jwt": "Asymmetrically-signed JWT assertion",
|
||||
"secret-http": "Client Secret over HTTP Basic",
|
||||
"secret-none": "No authentication",
|
||||
"secret-post": "Client Secret over HTTP POST",
|
||||
"secret-symmetric-jwt": "Client Secret via symmetrically-signed JWT assertion",
|
||||
"sector-identifier": "Sector Identifier URI",
|
||||
"signing": {
|
||||
"any": "Any allowed",
|
||||
"default": "Use server default",
|
||||
"ecdsa-256": "ECDSA using P-256 curve and SHA-256 hash algorithm",
|
||||
"ecdsa-384": "ECDSA using P-384 curve and SHA-384 hash algorithm",
|
||||
"ecdsa-512": "ECDSA using P-512 curve and SHA-512 hash algorithm",
|
||||
"hmac-256": "HMAC using SHA-256 hash algorithm",
|
||||
"hmac-384": "HMAC using SHA-384 hash algorithm",
|
||||
"hmac-512": "HMAC using SHA-512 hash algorithm",
|
||||
"none": "No digital signature",
|
||||
"rsassa-256": "RSASSA using SHA-256 hash algorithm",
|
||||
"rsassa-384": "RSASSA using SHA-384 hash algorithm",
|
||||
"rsassa-512": "RSASSA using SHA-512 hash algorithm"
|
||||
},
|
||||
"subject-type": "Subject Type",
|
||||
"terms": "Terms of Service",
|
||||
"terms-help": "URL for the Terms of Service of this client, will be displayed to the user",
|
||||
"token-signing-algorithm": "Token Endpoint Authentication Signing Algorithm",
|
||||
"tokens": "Tokens",
|
||||
"type": "Application Type",
|
||||
"type-native": "Native",
|
||||
"type-web": "Web",
|
||||
"unknown": "(Unknown)",
|
||||
"user-info-crypto-algorithm": "User Info Endpoint Encryption Algorithm",
|
||||
"user-info-crypto-method": "User Info Endpoint Encryption Method",
|
||||
"user-info-signing-algorithm": "User Info Endpoint Signing Algorithm"
|
||||
},
|
||||
"client-table": {
|
||||
"allow-introspection-tooltip": "This client can perform token introspection",
|
||||
"confirm": "Are you sure sure you would like to delete this client?",
|
||||
"dynamically-registered-tooltip": "This client was dynamically registered. Click to view registration access token",
|
||||
"match": {
|
||||
"contacts": "contacts",
|
||||
"description": "description",
|
||||
"homepage": "home page",
|
||||
"id": "id",
|
||||
"logo": "logo",
|
||||
"name": "name",
|
||||
"policy": "policy",
|
||||
"redirect": "redirect uri",
|
||||
"scope": "scope",
|
||||
"terms": "terms of service"
|
||||
},
|
||||
"matched-search": "Matched search:",
|
||||
"new": "New Client",
|
||||
"no-clients": "There are no registered clients on this server.",
|
||||
"no-matches": "There are no clients that match your search criteria.",
|
||||
"no-redirect": "NO REDIRECT URI",
|
||||
"registered": "Registrered",
|
||||
"search": "Search...",
|
||||
"whitelist": "Whitelist",
|
||||
"unknown": "at an unknown time"
|
||||
},
|
||||
"manage": "Manage Clients",
|
||||
"more-info": {
|
||||
"contacts": "Administrative Contacts:",
|
||||
"home": "Home Page:",
|
||||
"more": "more information",
|
||||
"policy": "Policy:",
|
||||
"terms": "Terms of Service:"
|
||||
},
|
||||
"newClient": "New Client"
|
||||
},
|
||||
"common": {
|
||||
"cancel": "Cancel",
|
||||
"client": "Client",
|
||||
"clients": "Clients",
|
||||
"close": "Close",
|
||||
"delete": "Delete",
|
||||
"description": "Description",
|
||||
"dynamically-registered": "This client was dynamically registered",
|
||||
"edit": "Edit",
|
||||
"expires": "Expires:",
|
||||
"information": "Information",
|
||||
"new": "New",
|
||||
"not-yet-implemented": "Not Yet Implemented",
|
||||
"not-yet-implemented-content": "The value of this field will be saved with the client, but the server does not currently process anything with it. Future versions of the server library will make use of this.",
|
||||
"revoke": "Revoke",
|
||||
"save": "Save",
|
||||
"scopes": "Scopes",
|
||||
"statistics": "Statistics"
|
||||
},
|
||||
"dynreg": {
|
||||
"client-id-placeholder": "Enter Client ID",
|
||||
"configuration-url": "Client Configuration URL",
|
||||
"edit-dynamically-registered": "Edit a Dynamically Registered Client",
|
||||
"edit-existing": "Edit an existing client",
|
||||
"edit-existing-help": "Paste in your client ID and registration access token to access the client.",
|
||||
"invalid-access-token": "Invalid client or registration access token.",
|
||||
"new-client": "Register a new client",
|
||||
"or": " - OR - ",
|
||||
"regtoken-placeholder": "Enter Registration Access Token",
|
||||
"warning": "<strong>Warning!</strong> You MUST protect your <b>Client ID</b>, <b>Client Secret (if provided)</b>, and your <b>Registration Access Token</b>. If you lose your Client ID or Registration Access Token, you will no longer have access to your client's registration records and you will need to register a new client.",
|
||||
"will-be-generated": "Will be generated"
|
||||
},
|
||||
"grant": {
|
||||
"manage-approved-sites": "Manage Approved Sites",
|
||||
"refresh": "Refresh",
|
||||
"grant-table": {
|
||||
"active-tokens": "Number of currently active access tokens",
|
||||
"application": "Application",
|
||||
"approved-sites": "Approved Sites",
|
||||
"authorized": "Authorized:",
|
||||
"dynamically-registered": "This client was dynamically registered",
|
||||
"expires": "Expires:",
|
||||
"last-accessed": "Last accessed:",
|
||||
"never": "Never",
|
||||
"no-sites": "You have not approved any sites.",
|
||||
"no-whitelisted": "You have not accessed any whitelisted sites.",
|
||||
"pre-approved": "These are sites that have been pre-approved by an administrator.",
|
||||
"text": "These are sites you have approved manually. If the same site asks for the same access in the future, it will be granted without prompting.",
|
||||
"unknown": "Unknown",
|
||||
"whitelist-note": "<b>NOTE:</b> If you revoke them here, they will automatically be re-approved on your next visit wthout prompting.",
|
||||
"whitelisted-site": "This site was whitelisted by an adminstrator",
|
||||
"whitelisted-sites": "Whitelisted Sites"
|
||||
}
|
||||
},
|
||||
"rsreg": {
|
||||
"resource-id-placeholder": "Enter Resource ID",
|
||||
"configuration-url": "Client Configuration URL",
|
||||
"edit": "Edit Protected Resource",
|
||||
"edit-existing": "Edit an existing protected resource",
|
||||
"edit-existing-help": "Paste in your ID and registration access token to access the resource's properties.",
|
||||
"invalid-access-token": "Invalid client or registration access token.",
|
||||
"new": "New Protected Resource",
|
||||
"new-resource": "Register a new protected resource",
|
||||
"or": " - OR - ",
|
||||
"regtoken-placeholder": "Enter Registration Access Token",
|
||||
"will-be-generated": "Will be generated",
|
||||
"warning": "<strong>Warning!</strong> You MUST protect your <b>Client ID</b>, <b>Client Secret (if provided)</b>, and your <b>Registration Access Token</b>. If you lose your Client ID or Registration Access Token, you will no longer have access to your client's registration records and you will need to register a new client.",
|
||||
"client-form": {
|
||||
"scope-help": "Scopes that this resource will be able to introspect tokens for."
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"manage": "Manage System Scopes",
|
||||
"scope-list": {
|
||||
"no-scopes": "NO SCOPES"
|
||||
},
|
||||
"system-scope-form": {
|
||||
"default": "default scope",
|
||||
"default-help": "Newly-created clients get this scope by default?",
|
||||
"description-help": "Human-readable text description",
|
||||
"description-placeholder": "Type a description",
|
||||
"restricted": "restricted",
|
||||
"restricted-help": "Restricted scopes are only usable by system administrators and are unavailable to dynamically registered clients and protected resources",
|
||||
"edit": "Edit Scope",
|
||||
"icon": "Icon",
|
||||
"new": "New Scope",
|
||||
"select-icon": "Select an icon",
|
||||
"structured": "is a structured scope",
|
||||
"structured-help": "Is the scope structured with structured values like <code>base:extension</code>?",
|
||||
"structured-param-help": "Human-readable description of the structured parameter",
|
||||
"subject-type": "Subject Type",
|
||||
"value": "Scope value",
|
||||
"value-help": "Single string with no spaces",
|
||||
"value-placeholder": "scope"
|
||||
},
|
||||
"system-scope-table": {
|
||||
"confirm": "Are you sure sure you would like to delete this scope? Clients that have this scope will still be able to ask for it.",
|
||||
"new": "New Scope",
|
||||
"text": "There are no system scopes defined. Clients may still have custom scopes.",
|
||||
"tooltip-restricted": "This scope can be used only by adminisrtators. It is not available for dynamic registration.",
|
||||
"tooltip-default": "This scope is automatically assigned to newly registered clients."
|
||||
}
|
||||
},
|
||||
"token": {
|
||||
"manage": "Manage Active Tokens",
|
||||
"token-table": {
|
||||
"access-tokens": "Access Tokens",
|
||||
"associated-id": "This access token was issued with an associated ID token.",
|
||||
"associated-refresh": "This access token was issued with an associated refresh token.",
|
||||
"click-to-display": "Click to display full token value",
|
||||
"confirm": "Are you sure sure you would like to revoke this token?",
|
||||
"confirm-refresh": "Are you sure sure you would like to revoke this refresh token and its associated access tokens?",
|
||||
"expires": "Expires",
|
||||
"no-access": "There are no active access tokens.",
|
||||
"no-refresh": "There are no active refresh tokens.",
|
||||
"number-of-tokens": "Number of associated access tokens",
|
||||
"refresh-tokens": "Refresh Tokens",
|
||||
"text": "Access tokens are usually short-lived and provide clients with access to specific resources. ID Tokens are specialized access tokens to facilitate log on using OpenID Connect.",
|
||||
"text-refresh": "Refresh tokens are usually long-lived and provide clients with the ability to get new access tokens without end-user involvement.",
|
||||
"token-info": "Token Information"
|
||||
}
|
||||
},
|
||||
"whitelist": {
|
||||
"confirm": "Are you sure you want to delete this whitelist entry?",
|
||||
"edit": "Edit Whitelist",
|
||||
"manage": "Manage Whitelisted Sites",
|
||||
"new": "New Whitelist",
|
||||
"whitelist": "Whitelist",
|
||||
"whitelist-form": {
|
||||
"allowed-scopes": "Allowed Scopes",
|
||||
"edit": "Edit Whitelisted Site",
|
||||
"new": "New Whitelisted Site",
|
||||
"scope-help": "List of scopes that will be automatically approved when this client makes a request",
|
||||
"scope-placeholder": "new scope"
|
||||
},
|
||||
"whitelist-table": {
|
||||
"no-sites": "There are no whitelisted sites. Use the <strong>whitelist</strong> button on the client management page to create one."
|
||||
}
|
||||
},
|
||||
"policy" : {
|
||||
"resource-sets": "Resource Sets",
|
||||
"edit-policy": "Edit Policy",
|
||||
"required-claims": "Required Claims",
|
||||
"policy-table": {
|
||||
"confirm": "Are you sure you want to delete this resource set?",
|
||||
"delete": "Delete",
|
||||
"edit": "Edit Policies",
|
||||
"email-address": "email address",
|
||||
"required-claims": "Users that you share this resource will with need to be able to present the following claims in order to access the resource.",
|
||||
"no-resource-sets": "There are no resource sets registered. Introduce a protected to this authorization server to let it register some.",
|
||||
"no-required-claims": "There are no required claims for this resource set: This resource set is inaccessible by others.",
|
||||
"share-email": "Share with email address",
|
||||
"shared-with": "Shared with:",
|
||||
"shared-nobody": "NOBODY",
|
||||
"shared-nobody-tooltip": "This resource is not accessible by anyone else, edit the policies and share it with someone.",
|
||||
"issuers": "Issuers",
|
||||
"claim": "Claim",
|
||||
"value": "Value"
|
||||
},
|
||||
"webfinger-error": "Error",
|
||||
"webfinger-error-description": "The server was unable to find an identity provider for <code>__email__</code>."
|
||||
},
|
||||
"copyright": "Powered by <a href=\"https://github.com/mitreid-connect/\">MITREid Connect <span class=\"label\">{0}</span></a> <span class=\"pull-right\">© 2015 The MITRE Corporation and MIT KIT.</span>.",
|
||||
"about": {
|
||||
"title": "About",
|
||||
"body": "\nThis OpenID Connect service is built from the MITREid Connect Open Source project, from \n<a href=\"http://www.mitre.org/\">The MITRE Corporation</a> and the <a href=\"http://kit.mit.edu/\">MIT Kerberos and Internet Trust Consortium</a>.\n</p>\n<p>\nMore information about the project can be found at \n<a href=\"http://github.com/mitreid-connect/\">MITREid Connect on GitHub</a>. \nThere, you can submit bug reports, give feedback, or even contribute code patches for additional features you'd like to see."
|
||||
},
|
||||
"statistics": {
|
||||
"title": "Statistics",
|
||||
"number_users": "Number of users: <span class=\"label label-info\" id=\"userCount\">{0}</span>",
|
||||
"number_clients": "Authorized clients: <span class=\"label label-info\" id=\"clientCount\">{0}</span>",
|
||||
"number_approvals": "Approved sites: <span class=\"label label-info\" id=\"approvalCount\">{0}</span>"
|
||||
},
|
||||
"home": {
|
||||
"title": "Home",
|
||||
"welcome": {
|
||||
"title": "Welcome!",
|
||||
"body": "\nOpenID Connect is an internet-scale federated identity protocol built on top of the OAuth2 authorization framework. \nOpenID Connect lets you log into a remote site using your identity without exposing your credentials, like a username and password.</p>\n<p><a class=\"btn btn-primary btn-large\" href=\"http://openid.net/connect/\">Learn more »</a>"
|
||||
},
|
||||
"more": "More",
|
||||
"about": {
|
||||
"title": "About",
|
||||
"body": "This OpenID Connect service is built from the MITREid Connect Open Source project, from \n<a href=\"http://www.mitre.org/\">The MITRE Corporation</a> and the <a href=\"http://kit.mit.edu/\">MIT Kerberos and Internet Trust Consortium</a>."
|
||||
},
|
||||
"contact": {
|
||||
"title": "Contact",
|
||||
"body": "\nFor more information or support, contact the administrators of this system.</p>\n<p><a class=\"btn\" href=\"mailto:idp@example.com?Subject=OpenID Connect\">Email »</a>"
|
||||
},
|
||||
"statistics": {
|
||||
"title": "Current Statistics",
|
||||
"loading": "Loading...",
|
||||
"number_users": "Number of users: <span class=\"label label-info\" id=\"userCount\">{0}</span>",
|
||||
"number_clients": "Authorized clients: <span class=\"label label-info\" id=\"clientCount\">{0}</span>",
|
||||
"number_approvals": "Approved sites: <span class=\"label label-info\" id=\"approvalCount\">{0}</span>"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"title": "Contact",
|
||||
"body": "To report bugs with the MITREid Connect software itself, use the \n<a href=\"https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/issues\">GitHub issue tracker</a>. \nFor problems relating to this server, contact the server's administrator."
|
||||
},
|
||||
"topbar": {
|
||||
"about": "About",
|
||||
"contact": "Contact",
|
||||
"statistics": "Statistics",
|
||||
"home": "Home",
|
||||
"login": "Log in",
|
||||
"logout": "Log out"
|
||||
},
|
||||
"sidebar": {
|
||||
"administrative": {
|
||||
"title": "Administrative",
|
||||
"manage_clients": "Manage Clients",
|
||||
"whitelisted_clients": "Whitelisted Clients",
|
||||
"blacklisted_clients": "Blacklisted Clients",
|
||||
"system_scopes": "System Scopes"
|
||||
},
|
||||
"personal": {
|
||||
"title": "Personal",
|
||||
"approved_sites": "Manage Approved Sites",
|
||||
"active_tokens": "Manage Active Tokens",
|
||||
"profile_information": "View Profile Information",
|
||||
"resource_policies": "Manage Protected Resource Policies"
|
||||
},
|
||||
"developer": {
|
||||
"title": "Developer",
|
||||
"client_registration": "Self-service client registration",
|
||||
"resource_registration": "Self-service protected resource registration"
|
||||
}
|
||||
},
|
||||
"manage": {
|
||||
"ok": "OK",
|
||||
"loading": "Loading",
|
||||
"title": "Management Console"
|
||||
},
|
||||
"approve": {
|
||||
"dynamically-registered-unknown": "at an unknown time",
|
||||
"title": "Approve Access",
|
||||
"error": {
|
||||
"not_granted": "Access could not be granted."
|
||||
},
|
||||
"required_for": "Approval Required for",
|
||||
"dynamically_registered": "This client was dynamically registered <span class=\"label label-info\" id=\"registrationTime\">{0}</span>.",
|
||||
"caution": {
|
||||
"title": "Caution",
|
||||
"message": {
|
||||
"none": "It has <span class=\"label label-important\">never</span> been approved previously.",
|
||||
"singular": "It has been approved <span class=\"label label-warning\">{0}</span> time previously.",
|
||||
"plural": "It has been approved <span class=\"label\">{0}</span> times previously."
|
||||
}
|
||||
},
|
||||
"more_information": "more information",
|
||||
"home_page": "Home page",
|
||||
"policy": "Policy",
|
||||
"terms": "Terms of Service",
|
||||
"contacts": "Administrative Contacts",
|
||||
"warning": "Warning",
|
||||
"no_redirect_uri": "This client does not have any redirect URIs registered and someone could be using a malicious URI here.",
|
||||
"redirect_uri": "You will be redirected to the following page if you click Approve: <code>{0}</code>",
|
||||
"pairwise": "This client uses a <b>pairwise</b> identifier, which makes it more difficult to correlate your identity between sites.",
|
||||
"no_scopes": "This client does not have any scopes registered and is therefore allowed to request <em>any</em> scopes available on the system. Proceed with caution.",
|
||||
"access_to": "Access to",
|
||||
"remember": {
|
||||
"title": "Remember this decision",
|
||||
"until_revoke": "remember this decision until I revoke it",
|
||||
"one_hour": "remember this decision for one hour",
|
||||
"next_time": "prompt me again next time"
|
||||
},
|
||||
"do_authorize": "Do you authorize",
|
||||
"label": {
|
||||
"authorize": "Authorize",
|
||||
"deny": "Deny"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,404 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.
|
||||
*******************************************************************************/
|
||||
|
||||
var ResourceSetModel = Backbone.Model.extend({
|
||||
|
||||
});
|
||||
|
||||
var ResourceSetCollection = Backbone.Collection.extend({
|
||||
model: ResourceSetModel,
|
||||
url: 'api/claims'
|
||||
});
|
||||
|
||||
var ClaimModel = Backbone.Model.extend({
|
||||
|
||||
});
|
||||
|
||||
var ClaimCollection = Backbone.Collection.extend({
|
||||
model: ClaimModel
|
||||
});
|
||||
|
||||
var ResourceSetListView = Backbone.View.extend({
|
||||
tagName: 'span',
|
||||
|
||||
initialize:function (options) {
|
||||
this.options = options;
|
||||
},
|
||||
|
||||
load:function(callback) {
|
||||
if (this.model.isFetched &&
|
||||
this.options.clientList.isFetched &&
|
||||
this.options.systemScopeList.isFetched) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
$('#loadingbox').sheet('show');
|
||||
$('#loading').html(
|
||||
'<span class="label" id="loading-resourcesets">' + $.t('policy.resource-sets') + '</span> ' +
|
||||
'<span class="label" id="loading-clients">' + $.t('common.clients') + '</span> ' +
|
||||
'<span class="label" id="loading-scopes">' + $.t('common.scopes') + '</span> '
|
||||
);
|
||||
|
||||
$.when(this.model.fetchIfNeeded({success:function(e) {$('#loading-resourcesets').addClass('label-success');}}),
|
||||
this.options.clientList.fetchIfNeeded({success:function(e) {$('#loading-clients').addClass('label-success');}}),
|
||||
this.options.systemScopeList.fetchIfNeeded({success:function(e) {$('#loading-scopes').addClass('label-success');}}))
|
||||
.done(function() {
|
||||
$('#loadingbox').sheet('hide');
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
events: {
|
||||
"click .refresh-table":"refreshTable"
|
||||
},
|
||||
|
||||
render:function (eventName) {
|
||||
$(this.el).html($('#tmpl-resource-set-table').html());
|
||||
|
||||
var _self = this;
|
||||
|
||||
_.each(this.model.models, function (resourceSet) {
|
||||
|
||||
// look up client
|
||||
var client = this.options.clientList.getByClientId(resourceSet.get('clientId'));
|
||||
|
||||
// if there's no client ID, this is an error!
|
||||
if (client != null) {
|
||||
var view = new ResourceSetView({model: resourceSet, client: client, systemScopeList: _self.options.systemScopeList});
|
||||
view.parentView = _self;
|
||||
$('#resource-set-table', this.el).append(view.render().el);
|
||||
}
|
||||
|
||||
}, this);
|
||||
|
||||
this.togglePlaceholder();
|
||||
$(this.el).i18n();
|
||||
return this;
|
||||
},
|
||||
|
||||
togglePlaceholder:function() {
|
||||
if (this.model.length > 0) {
|
||||
$('#resource-set-table', this.el).show();
|
||||
$('#resource-set-table-empty', this.el).hide();
|
||||
} else {
|
||||
$('#resource-set-table', this.el).hide();
|
||||
$('#resource-set-table-empty', this.el).show();
|
||||
}
|
||||
},
|
||||
|
||||
refreshTable:function(e) {
|
||||
e.preventDefault();
|
||||
var _self = this;
|
||||
$('#loadingbox').sheet('show');
|
||||
$('#loading').html(
|
||||
'<span class="label" id="loading-resourcesets">' + $.t('policy.resource-sets') + '</span> ' +
|
||||
'<span class="label" id="loading-clients">' + $.t('common.clients') + '</span> ' +
|
||||
'<span class="label" id="loading-scopes">' + $.t('common.scopes') + '</span> '
|
||||
);
|
||||
|
||||
$.when(this.model.fetch({success:function(e) {$('#loading-resourcesets').addClass('label-success');}}),
|
||||
this.options.clientList.fetch({success:function(e) {$('#loading-clients').addClass('label-success');}}),
|
||||
this.options.systemScopeList.fetch({success:function(e) {$('#loading-scopes').addClass('label-success');}}))
|
||||
.done(function() {
|
||||
$('#loadingbox').sheet('hide');
|
||||
_self.render();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
var ResourceSetView = Backbone.View.extend({
|
||||
tagName: 'tr',
|
||||
|
||||
initialize:function(options) {
|
||||
this.options = options;
|
||||
if (!this.template) {
|
||||
this.template = _.template($('#tmpl-resource-set').html());
|
||||
}
|
||||
|
||||
if (!this.scopeTemplate) {
|
||||
this.scopeTemplate = _.template($('#tmpl-scope-list').html());
|
||||
}
|
||||
|
||||
if (!this.moreInfoTemplate) {
|
||||
this.moreInfoTemplate = _.template($('#tmpl-client-more-info-block').html());
|
||||
}
|
||||
|
||||
this.model.bind('change', this.render, this);
|
||||
},
|
||||
|
||||
render:function(eventName) {
|
||||
|
||||
var json = {rs: this.model.toJSON(), client: this.options.client.toJSON()};
|
||||
|
||||
this.$el.html(this.template(json));
|
||||
|
||||
$('.scope-list', this.el).html(this.scopeTemplate({scopes: this.model.get('scopes'), systemScopes: this.options.systemScopeList}));
|
||||
|
||||
$('.client-more-info-block', this.el).html(this.moreInfoTemplate({client: this.options.client.toJSON()}));
|
||||
|
||||
$(this.el).i18n();
|
||||
return this;
|
||||
},
|
||||
|
||||
events:{
|
||||
'click .btn-edit': 'editPolicies',
|
||||
'click .btn-delete': 'deleteResourceSet',
|
||||
'click .toggleMoreInformation': 'toggleMoreInformation'
|
||||
},
|
||||
|
||||
editPolicies:function(e) {
|
||||
e.preventDefault();
|
||||
app.navigate('user/policy/' + this.model.get('id'), {trigger: true});
|
||||
},
|
||||
|
||||
deleteResourceSet:function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (confirm($.t('policy.policy-table.confirm'))) {
|
||||
var _self = this;
|
||||
|
||||
this.model.destroy({
|
||||
success:function () {
|
||||
_self.$el.fadeTo("fast", 0.00, function () { //fade
|
||||
$(this).slideUp("fast", function () { //slide up
|
||||
$(this).remove(); //then remove from the DOM
|
||||
_self.parentView.togglePlaceholder();
|
||||
});
|
||||
});
|
||||
},
|
||||
error:function (error, response) {
|
||||
console.log("An error occurred when deleting a resource set");
|
||||
|
||||
//Pull out the response text.
|
||||
var responseJson = JSON.parse(response.responseText);
|
||||
|
||||
//Display an alert with an error message
|
||||
$('#modalAlert div.modal-header').html(responseJson.error);
|
||||
$('#modalAlert div.modal-body').html(responseJson.error_description);
|
||||
|
||||
$("#modalAlert").modal({ // wire up the actual modal functionality and show the dialog
|
||||
"backdrop" : "static",
|
||||
"keyboard" : true,
|
||||
"show" : true // ensure the modal is shown immediately
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
_self.parentView.delegateEvents();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
},
|
||||
|
||||
toggleMoreInformation:function(e) {
|
||||
e.preventDefault();
|
||||
if ($('.moreInformation', this.el).is(':visible')) {
|
||||
// hide it
|
||||
$('.moreInformation', this.el).hide('fast');
|
||||
$('.toggleMoreInformation i', this.el).attr('class', 'icon-chevron-right');
|
||||
$('.moreInformationContainer', this.el).removeClass('alert').removeClass('alert-info').addClass('muted');
|
||||
|
||||
} else {
|
||||
// show it
|
||||
$('.moreInformation', this.el).show('fast');
|
||||
$('.toggleMoreInformation i', this.el).attr('class', 'icon-chevron-down');
|
||||
$('.moreInformationContainer', this.el).addClass('alert').addClass('alert-info').removeClass('muted');
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
var ClaimListView = Backbone.View.extend({
|
||||
tagName: 'span',
|
||||
|
||||
initialize:function(options) {
|
||||
this.options = options;
|
||||
},
|
||||
|
||||
load:function(callback) {
|
||||
if (this.model.isFetched) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
$('#loadingbox').sheet('show');
|
||||
$('#loading').html(
|
||||
'<span class="label" id="loading-claims">' + $.t('policy.required-claims') + '</span> '
|
||||
);
|
||||
|
||||
$.when(this.model.fetchIfNeeded({success:function(e) {$('#loading-claims').addClass('label-success');}}))
|
||||
.done(function() {
|
||||
$('#loadingbox').sheet('hide');
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
events:{
|
||||
'click .btn-save':'savePolicy',
|
||||
'click .btn-cancel':'cancel',
|
||||
'click #add-email':'addClaim'
|
||||
},
|
||||
|
||||
cancel:function(e) {
|
||||
e.preventDefault();
|
||||
app.navigate('user/policy', {trigger: true});
|
||||
},
|
||||
|
||||
savePolicy:function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var _self = this;
|
||||
|
||||
console.log(this);
|
||||
|
||||
this.model.sync('update', this.model, {
|
||||
success:function() {
|
||||
// update our copy of the resource set object (if we have it)
|
||||
if (_self.options.rs != null) {
|
||||
_self.options.rs.set({claimsRequired: _self.model.toJSON()}, {trigger: false});
|
||||
}
|
||||
|
||||
app.navigate('user/policy', {trigger: true});
|
||||
},
|
||||
error:function (error, response) {
|
||||
console.log("An error occurred when saving a policy set");
|
||||
|
||||
//Pull out the response text.
|
||||
var responseJson = JSON.parse(response.responseText);
|
||||
|
||||
//Display an alert with an error message
|
||||
$('#modalAlert div.modal-header').html(responseJson.error);
|
||||
$('#modalAlert div.modal-body').html(responseJson.error_description);
|
||||
|
||||
$("#modalAlert").modal({ // wire up the actual modal functionality and show the dialog
|
||||
"backdrop" : "static",
|
||||
"keyboard" : true,
|
||||
"show" : true // ensure the modal is shown immediately
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
addClaim:function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// post to the webfinger helper and get the response back
|
||||
|
||||
var _self = this;
|
||||
|
||||
var email = $('#email', this.el).val();
|
||||
|
||||
var base = $('base').attr('href');
|
||||
$.getJSON(base + '/api/emailsearch?' + $.param({'identifier': email}), function(data) {
|
||||
|
||||
var claim = new ClaimModel(data);
|
||||
_self.model.add(claim, {'trigger': false});
|
||||
_self.render();
|
||||
|
||||
}).error(function(jqXHR, textStatus, errorThrown) {
|
||||
console.log("An error occurred when doing a webfinger lookup", errorThrown);
|
||||
|
||||
//Display an alert with an error message
|
||||
$('#modalAlert div.modal-header').html($.t('policy.webfinger-error'));
|
||||
$('#modalAlert div.modal-body').html($.t('policy.webfinger-error-description', {email: email}));
|
||||
|
||||
$("#modalAlert").modal({ // wire up the actual modal functionality and show the dialog
|
||||
"backdrop" : "static",
|
||||
"keyboard" : true,
|
||||
"show" : true // ensure the modal is shown immediately
|
||||
});
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
togglePlaceholder:function() {
|
||||
if (this.model.length > 0) {
|
||||
$('#required-claim-table', this.el).show();
|
||||
$('#required-claim-table-empty', this.el).hide();
|
||||
} else {
|
||||
$('#required-claim-table', this.el).hide();
|
||||
$('#required-claim-table-empty', this.el).show();
|
||||
}
|
||||
},
|
||||
|
||||
render:function (eventName) {
|
||||
$(this.el).html($('#tmpl-required-claim-table').html());
|
||||
|
||||
var _self = this;
|
||||
|
||||
_.each(this.model.models, function (claim) {
|
||||
|
||||
var view = new ClaimView({model: claim});
|
||||
view.parentView = _self;
|
||||
$('#required-claim-table', this.el).append(view.render().el);
|
||||
|
||||
}, this);
|
||||
|
||||
this.togglePlaceholder();
|
||||
$(this.el).i18n();
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var ClaimView = Backbone.View.extend({
|
||||
tagName: 'tr',
|
||||
|
||||
initialize:function(options) {
|
||||
this.options = options;
|
||||
|
||||
if (!this.template) {
|
||||
this.template = _.template($('#tmpl-required-claim').html());
|
||||
}
|
||||
},
|
||||
|
||||
events:{
|
||||
'click .btn-remove':'removeClaim'
|
||||
},
|
||||
|
||||
removeClaim:function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var _self = this;
|
||||
|
||||
this.model.collection.remove(this.model);
|
||||
_self.$el.fadeTo("fast", 0.00, function () { //fade
|
||||
$(this).slideUp("fast", function () { //slide up
|
||||
$(this).remove(); //then remove from the DOM
|
||||
_self.parentView.togglePlaceholder();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
|
||||
render:function (eventName) {
|
||||
var json = this.model.toJSON();
|
||||
|
||||
this.$el.html(this.template(json));
|
||||
|
||||
$(this.el).i18n();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
});
|
|
@ -0,0 +1,137 @@
|
|||
<!--
|
||||
Copyright 2015 The MITRE Corporation
|
||||
and the MIT Kerberos and 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.
|
||||
-->
|
||||
<!-- policy: resource sets and claims -->
|
||||
|
||||
<script type="text/html" id="tmpl-resource-set-table">
|
||||
<div class="well well-small">
|
||||
<button class="btn btn-small refresh-table"><i class="icon-refresh"></i> <span data-i18n="common.refresh">Refresh</span></button>
|
||||
</div>
|
||||
|
||||
<div id="resource-set-table-empty" class="alert alert-info" data-i18n="policy.policy-table.no-resource-sets">
|
||||
There are no resource sets registered. Introduce a protected to this authorization server to let it register some.
|
||||
</div>
|
||||
|
||||
<table id="resource-set-table" class="table table-hover table-striped">
|
||||
<thead>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="well well-small">
|
||||
<button class="btn btn-small refresh-table"><i class="icon-refresh"></i> <span data-i18n="common.refresh">Refresh</span></button>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tmpl-resource-set">
|
||||
<td>
|
||||
<%- rs.name %>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<span title="<%- client.clientId %>"><%- client.clientName != null ? client.clientName : ( client.clientId.substr(0,8) + '...' ) %></span>
|
||||
<div class="client-more-info-block"></div>
|
||||
<div class="scope-list"></div>
|
||||
<div><span class="text-warning" data-i18n="policy.policy-table.shared-with"><i class="icon-share"></i> Shared with:</span>
|
||||
<% if (!_.isEmpty(rs.claimsRequired)) {
|
||||
_.each(rs.claimsRequired, function(claim) { %>
|
||||
<span class="label label-info"><%- claim.value %></span>
|
||||
<% });
|
||||
} else { %>
|
||||
<span class="label label-important" data-i18n="policy.policy-table.shared-nobody;[title]policy.policy-table.shared-nobody-tooltip" title="This resource is not accessible by anyone else, edit the policies and share it with someone.">NOBODY</span>
|
||||
<% } %>
|
||||
|
||||
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<div class="btn-group pull-right">
|
||||
<button class="btn btn-edit"><i class="icon-edit"></i> <span data-i18n="policy.policy-table.edit">Edit Policies</span></button>
|
||||
<button class="btn btn-danger btn-delete"><i class="icon-trash icon-white"></i> <span data-i18n="policy.policy-table.delete">Delete</span></button>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tmpl-required-claim-table">
|
||||
<div class="well well-small">
|
||||
<button class="btn btn-small btn-save btn-success"><i class="icon-ok-circle icon-white"></i> <span data-i18n="common.save">Save</span></button>
|
||||
<button class="btn btn-small btn-cancel"><i class="icon-ban-circle"></i> <span data-i18n="common.cancel">Cancel</span></button>
|
||||
</div>
|
||||
|
||||
<div id="add-required-claim">
|
||||
<form class="form-horizontal">
|
||||
<fieldset>
|
||||
<input type="text" id="email" placeholder="email address" data-i18n="[placeholder]policy.policy-table.email-address" />
|
||||
<button id="add-email" class="btn btn-info"><i class="icon-share icon-white"></i> <span data-i18n="policy.policy-table.share-email">Share with email address</span></button>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info" data-i18n="policy.policy-table.required-claims">
|
||||
Users that you share this resource will with need to be able to present the following claims in order to access the resource.
|
||||
</div>
|
||||
|
||||
<div id="required-claim-table-empty" class="alert alert-danger" data-i18n="policy.policy-table.no-required-claims">
|
||||
There are no required claims for this resource set: This resource set is inaccessible by others.
|
||||
</div>
|
||||
|
||||
<table id="required-claim-table" class="table table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-i18n="policy.policy-table.issuers">Issuers</th>
|
||||
<th data-i18n="policy.policy-table.claim">Claim</th>
|
||||
<th data-i18n="policy.policy-table.value">Value</th>
|
||||
<th></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="well well-small">
|
||||
<button class="btn btn-small btn-save btn-success"><i class="icon-ok-circle icon-white"></i> <span data-i18n="common.save">Save</span></button>
|
||||
<button class="btn btn-small btn-cancel"><i class="icon-ban-circle"></i> <span data-i18n="common.cancel">Cancel</span></button>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tmpl-required-claim">
|
||||
<td>
|
||||
<% _.each(issuer, function(issuer) { %>
|
||||
<span class="label label-info"><%- issuer %></span>
|
||||
<% }); %>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<%- name %>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<%- value %>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<div class="btn-group pull-right">
|
||||
<button class="btn btn-danger btn-remove"><i class="icon-trash icon-white"></i> <span data-i18n="policy.policy-table.remove">Remove</span></button>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
</script>
|
||||
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2015 The MITRE Corporation
|
||||
and the MIT Kerberos and 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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.mitre</groupId>
|
||||
<artifactId>openid-connect-parent</artifactId>
|
||||
<version>1.2.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>uma-server</artifactId>
|
||||
<name>UMA Server Library</name>
|
||||
<description>User Managed Access (UMA) extension of the MITREid Connect server</description>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${java-version}</source>
|
||||
<target>${java-version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.mitre</groupId>
|
||||
<artifactId>openid-connect-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mitre</groupId>
|
||||
<artifactId>openid-connect-client</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,56 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.PermissionTicket;
|
||||
import org.mitre.uma.repository.PermissionRepository;
|
||||
import org.mitre.util.jpa.JpaUtil;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Repository
|
||||
public class JpaPermissionRepository implements PermissionRepository {
|
||||
|
||||
@PersistenceContext
|
||||
private EntityManager em;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public PermissionTicket save(PermissionTicket p) {
|
||||
return JpaUtil.saveOrUpdate(p.getId(), em, p);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.uma.repository.PermissionRepository#getByTicket(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public PermissionTicket getByTicket(String ticket) {
|
||||
TypedQuery<PermissionTicket> query = em.createNamedQuery(PermissionTicket.QUERY_TICKET, PermissionTicket.class);
|
||||
query.setParameter(PermissionTicket.PARAM_TICKET, ticket);
|
||||
return JpaUtil.getSingleResult(query.getResultList());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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 java.util.Collection;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
import javax.persistence.TypedQuery;
|
||||
|
||||
import org.mitre.uma.model.ResourceSet;
|
||||
import org.mitre.uma.repository.ResourceSetRepository;
|
||||
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
|
||||
public class JpaResourceSetRepository implements ResourceSetRepository {
|
||||
|
||||
@PersistenceContext
|
||||
private EntityManager em;
|
||||
private static Logger logger = LoggerFactory.getLogger(JpaResourceSetRepository.class);
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public ResourceSet save(ResourceSet rs) {
|
||||
return JpaUtil.saveOrUpdate(rs.getId(), em, rs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceSet getById(Long id) {
|
||||
return em.find(ResourceSet.class, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void remove(ResourceSet rs) {
|
||||
ResourceSet found = getById(rs.getId());
|
||||
if (found != null) {
|
||||
em.remove(found);
|
||||
} else {
|
||||
logger.info("Tried to remove unknown resource set: " + rs.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourceSet> getAllForOwner(String owner) {
|
||||
TypedQuery<ResourceSet> query = em.createNamedQuery(ResourceSet.QUERY_BY_OWNER, ResourceSet.class);
|
||||
query.setParameter(ResourceSet.PARAM_OWNER, owner);
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourceSet> getAllForOwnerAndClient(String owner, String clientId) {
|
||||
TypedQuery<ResourceSet> query = em.createNamedQuery(ResourceSet.QUERY_BY_OWNER_AND_CLIENT, ResourceSet.class);
|
||||
query.setParameter(ResourceSet.PARAM_OWNER, owner);
|
||||
query.setParameter(ResourceSet.PARAM_CLIENTID, clientId);
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.service.impl;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.mitre.oauth2.service.SystemScopeService;
|
||||
import org.mitre.uma.model.Permission;
|
||||
import org.mitre.uma.model.PermissionTicket;
|
||||
import org.mitre.uma.model.ResourceSet;
|
||||
import org.mitre.uma.repository.PermissionRepository;
|
||||
import org.mitre.uma.service.PermissionService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.oauth2.common.exceptions.InsufficientScopeException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Service
|
||||
public class DefaultPermissionService implements PermissionService {
|
||||
|
||||
@Autowired
|
||||
private PermissionRepository repository;
|
||||
|
||||
@Autowired
|
||||
private SystemScopeService scopeService;
|
||||
|
||||
private Long permissionExpirationSeconds = 60L * 60L; // 1 hr
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.uma.service.PermissionService#create(org.mitre.uma.model.ResourceSet, java.util.Set)
|
||||
*/
|
||||
@Override
|
||||
public PermissionTicket createTicket(ResourceSet resourceSet, Set<String> scopes) {
|
||||
|
||||
// check to ensure that the scopes requested are a subset of those in the resource set
|
||||
|
||||
if (!scopeService.scopesMatch(resourceSet.getScopes(), scopes)) {
|
||||
throw new InsufficientScopeException("Scopes of resource set are not enough for requested permission.");
|
||||
}
|
||||
|
||||
Permission perm = new Permission();
|
||||
perm.setResourceSet(resourceSet);
|
||||
perm.setScopes(scopes);
|
||||
|
||||
PermissionTicket ticket = new PermissionTicket();
|
||||
ticket.setPermission(perm);
|
||||
ticket.setTicket(UUID.randomUUID().toString());
|
||||
ticket.setExpiration(new Date(System.currentTimeMillis() + permissionExpirationSeconds * 1000L));
|
||||
|
||||
return repository.save(ticket);
|
||||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.uma.service.PermissionService#getByTicket(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public PermissionTicket getByTicket(String ticket) {
|
||||
return repository.getByTicket(ticket);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.uma.service.PermissionService#updateTicket(org.mitre.uma.model.PermissionTicket)
|
||||
*/
|
||||
@Override
|
||||
public PermissionTicket updateTicket(PermissionTicket ticket) {
|
||||
if (ticket.getId() != null) {
|
||||
return repository.save(ticket);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.service.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mitre.uma.model.ResourceSet;
|
||||
import org.mitre.uma.repository.ResourceSetRepository;
|
||||
import org.mitre.uma.service.ResourceSetService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Service
|
||||
@Primary
|
||||
public class DefaultResourceSetService implements ResourceSetService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultResourceSetService.class);
|
||||
|
||||
@Autowired
|
||||
private ResourceSetRepository repository;
|
||||
|
||||
@Override
|
||||
public ResourceSet saveNew(ResourceSet rs) {
|
||||
|
||||
if (rs.getId() != null) {
|
||||
throw new IllegalArgumentException("Can't save a new resource set with an ID already set to it.");
|
||||
}
|
||||
|
||||
ResourceSet saved = repository.save(rs);
|
||||
|
||||
return saved;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceSet getById(Long id) {
|
||||
return repository.getById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceSet update(ResourceSet oldRs, ResourceSet newRs) {
|
||||
|
||||
if (oldRs.getId() == null || newRs.getId() == null
|
||||
|| oldRs.getId() != newRs.getId()) {
|
||||
|
||||
throw new IllegalArgumentException("Resource set IDs mismatched");
|
||||
|
||||
}
|
||||
|
||||
newRs.setOwner(oldRs.getOwner()); // preserve the owner tag across updates
|
||||
newRs.setClientId(oldRs.getClientId()); // preserve the client id across updates
|
||||
|
||||
ResourceSet saved = repository.save(newRs);
|
||||
|
||||
return saved;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(ResourceSet rs) {
|
||||
repository.remove(rs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourceSet> getAllForOwner(String owner) {
|
||||
return repository.getAllForOwner(owner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourceSet> getAllForOwnerAndClient(String owner, String clientId) {
|
||||
return repository.getAllForOwnerAndClient(owner, clientId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.service.impl;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.mitre.jwt.signer.service.JWTSigningAndValidationService;
|
||||
import org.mitre.oauth2.model.AuthenticationHolderEntity;
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||
import org.mitre.oauth2.repository.AuthenticationHolderRepository;
|
||||
import org.mitre.oauth2.service.ClientDetailsEntityService;
|
||||
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
||||
import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
|
||||
import org.mitre.uma.model.PermissionTicket;
|
||||
import org.mitre.uma.service.UmaTokenService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.nimbusds.jose.JWSAlgorithm;
|
||||
import com.nimbusds.jose.JWSHeader;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.SignedJWT;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Service("defaultUmaTokenService")
|
||||
public class DefaultUmaTokenService implements UmaTokenService {
|
||||
|
||||
@Autowired
|
||||
private AuthenticationHolderRepository authenticationHolderRepository;
|
||||
|
||||
@Autowired
|
||||
private OAuth2TokenEntityService tokenService;
|
||||
|
||||
@Autowired
|
||||
private ClientDetailsEntityService clientService;
|
||||
|
||||
@Autowired
|
||||
private ConfigurationPropertiesBean config;
|
||||
|
||||
@Autowired
|
||||
private JWTSigningAndValidationService jwtService;
|
||||
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenEntity createRequestingPartyToken(OAuth2Authentication o2auth, PermissionTicket ticket) {
|
||||
OAuth2AccessTokenEntity token = new OAuth2AccessTokenEntity();
|
||||
AuthenticationHolderEntity authHolder = new AuthenticationHolderEntity();
|
||||
authHolder.setAuthentication(o2auth);
|
||||
authHolder = authenticationHolderRepository.save(authHolder);
|
||||
|
||||
token.setAuthenticationHolder(authHolder);
|
||||
|
||||
ClientDetailsEntity client = clientService.loadClientByClientId(o2auth.getOAuth2Request().getClientId());
|
||||
token.setClient(client);
|
||||
|
||||
token.setPermissions(Sets.newHashSet(ticket.getPermission()));
|
||||
|
||||
|
||||
JWTClaimsSet claims = new JWTClaimsSet();
|
||||
|
||||
claims.setAudience(Lists.newArrayList(ticket.getPermission().getResourceSet().getId().toString()));
|
||||
claims.setIssuer(config.getIssuer());
|
||||
claims.setJWTID(UUID.randomUUID().toString());
|
||||
|
||||
if (config.getRqpTokenLifeTime() != null) {
|
||||
Date exp = new Date(System.currentTimeMillis() + config.getRqpTokenLifeTime() * 1000L);
|
||||
|
||||
claims.setExpirationTime(exp);
|
||||
token.setExpiration(exp);
|
||||
}
|
||||
|
||||
|
||||
JWSAlgorithm signingAlgorithm = jwtService.getDefaultSigningAlgorithm();
|
||||
SignedJWT signed = new SignedJWT(new JWSHeader(signingAlgorithm), claims);
|
||||
|
||||
jwtService.signJwt(signed);
|
||||
|
||||
token.setJwt(signed);
|
||||
|
||||
tokenService.saveAccessToken(token);
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.service.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.mitre.uma.model.Claim;
|
||||
import org.mitre.uma.service.ClaimsProcessingService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* Tests if all the claims in the required set have a matching
|
||||
* value in the supplied set.
|
||||
*
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Service("matchAllClaimsProcessor")
|
||||
public class MatchAllClaimsProcessor implements ClaimsProcessingService {
|
||||
|
||||
@Override
|
||||
public Collection<Claim> claimsAreSatisfied(Collection<Claim> claimsRequired, Collection<Claim> claimsSupplied) {
|
||||
|
||||
Collection<Claim> claimsUnmatched = new HashSet<>(claimsRequired);
|
||||
|
||||
// see if each of the required claims has a counterpart in the supplied claims set
|
||||
for (Claim required : claimsRequired) {
|
||||
for (Claim supplied : claimsSupplied) {
|
||||
|
||||
if (required.getIssuer().containsAll(supplied.getIssuer())) {
|
||||
// it's from the right issuer
|
||||
|
||||
if (required.getName().equals(supplied.getName()) &&
|
||||
required.getValue().equals(supplied.getValue())) {
|
||||
|
||||
// the claim matched, pull it from the set
|
||||
claimsUnmatched.remove(required);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if there's anything left then the claims aren't satisfied, return the leftovers
|
||||
return claimsUnmatched;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
public class ExternalLoginAuthoritiesMapper implements GrantedAuthoritiesMapper {
|
||||
|
||||
private static final GrantedAuthority ROLE_EXTERNAL_USER = new SimpleGrantedAuthority("ROLE_EXTERNAL_USER");
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> mapAuthorities(Collection<? extends GrantedAuthority> authorities) {
|
||||
Set<GrantedAuthority> out = Sets.newHashSet(authorities);
|
||||
out.add(ROLE_EXTERNAL_USER);
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.view;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
|
||||
import org.mitre.openid.connect.view.HttpCodeView;
|
||||
import org.mitre.openid.connect.view.JsonEntityView;
|
||||
import org.mitre.uma.model.ResourceSet;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.validation.BeanPropertyBindingResult;
|
||||
import org.springframework.web.servlet.view.AbstractView;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.gson.ExclusionStrategy;
|
||||
import com.google.gson.FieldAttributes;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.LongSerializationPolicy;
|
||||
|
||||
@Component(ResourceSetEntityAbbreviatedView.VIEWNAME)
|
||||
public class ResourceSetEntityAbbreviatedView extends AbstractView {
|
||||
private static Logger logger = LoggerFactory.getLogger(JsonEntityView.class);
|
||||
|
||||
public static final String VIEWNAME = "resourceSetEntityAbbreviatedView";
|
||||
|
||||
public static final String LOCATION = "location";
|
||||
|
||||
@Autowired
|
||||
private ConfigurationPropertiesBean config;
|
||||
|
||||
private Gson gson = new GsonBuilder()
|
||||
.setExclusionStrategies(new ExclusionStrategy() {
|
||||
|
||||
@Override
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
// skip the JPA binding wrapper
|
||||
if (clazz.equals(BeanPropertyBindingResult.class)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
})
|
||||
.serializeNulls()
|
||||
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
|
||||
.setLongSerializationPolicy(LongSerializationPolicy.STRING)
|
||||
.create();
|
||||
|
||||
@Override
|
||||
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
|
||||
|
||||
response.setContentType("application/json");
|
||||
|
||||
|
||||
HttpStatus code = (HttpStatus) model.get(HttpCodeView.CODE);
|
||||
if (code == null) {
|
||||
code = HttpStatus.OK; // default to 200
|
||||
}
|
||||
|
||||
response.setStatus(code.value());
|
||||
|
||||
String location = (String) model.get(LOCATION);
|
||||
if (!Strings.isNullOrEmpty(location)) {
|
||||
response.setHeader(HttpHeaders.LOCATION, location);
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
Writer out = response.getWriter();
|
||||
ResourceSet rs = (ResourceSet) model.get(JsonEntityView.ENTITY);
|
||||
|
||||
JsonObject o = new JsonObject();
|
||||
|
||||
o.addProperty("_id", rs.getId().toString()); // set the ID to a string
|
||||
o.addProperty("user_access_policy_uri", config.getIssuer() + "manage/user/policy/" + rs.getId());
|
||||
|
||||
|
||||
gson.toJson(o, out);
|
||||
|
||||
} catch (IOException e) {
|
||||
|
||||
logger.error("IOException in ResourceSetEntityView.java: ", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.view;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
|
||||
import org.mitre.openid.connect.view.JsonEntityView;
|
||||
import org.mitre.uma.model.ResourceSet;
|
||||
import org.mitre.util.JsonUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.validation.BeanPropertyBindingResult;
|
||||
import org.springframework.web.servlet.view.AbstractView;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.gson.ExclusionStrategy;
|
||||
import com.google.gson.FieldAttributes;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.LongSerializationPolicy;
|
||||
|
||||
@Component(ResourceSetEntityView.VIEWNAME)
|
||||
public class ResourceSetEntityView extends AbstractView {
|
||||
private static Logger logger = LoggerFactory.getLogger(JsonEntityView.class);
|
||||
|
||||
public static final String VIEWNAME = "resourceSetEntityView";
|
||||
|
||||
@Autowired
|
||||
private ConfigurationPropertiesBean config;
|
||||
|
||||
private Gson gson = new GsonBuilder()
|
||||
.setExclusionStrategies(new ExclusionStrategy() {
|
||||
|
||||
@Override
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
// skip the JPA binding wrapper
|
||||
if (clazz.equals(BeanPropertyBindingResult.class)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
})
|
||||
.serializeNulls()
|
||||
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
|
||||
.setLongSerializationPolicy(LongSerializationPolicy.STRING)
|
||||
.create();
|
||||
|
||||
@Override
|
||||
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
|
||||
|
||||
response.setContentType("application/json");
|
||||
|
||||
|
||||
HttpStatus code = (HttpStatus) model.get("code");
|
||||
if (code == null) {
|
||||
code = HttpStatus.OK; // default to 200
|
||||
}
|
||||
|
||||
response.setStatus(code.value());
|
||||
|
||||
String location = (String) model.get("location");
|
||||
if (!Strings.isNullOrEmpty(location)) {
|
||||
response.setHeader(HttpHeaders.LOCATION, location);
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
Writer out = response.getWriter();
|
||||
ResourceSet rs = (ResourceSet) model.get("entity");
|
||||
|
||||
JsonObject o = new JsonObject();
|
||||
|
||||
o.addProperty("_id", rs.getId().toString()); // send the id as a string
|
||||
o.addProperty("user_access_policy_uri", config.getIssuer() + "manage/resource/" + rs.getId());
|
||||
o.addProperty("name", rs.getName());
|
||||
o.addProperty("uri", rs.getUri());
|
||||
o.addProperty("type", rs.getType());
|
||||
o.add("scopes", JsonUtils.getAsArray(rs.getScopes()));
|
||||
o.addProperty("icon_uri", rs.getIconUri());
|
||||
|
||||
gson.toJson(o, out);
|
||||
|
||||
} catch (IOException e) {
|
||||
|
||||
logger.error("IOException in ResourceSetEntityView.java: ", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,236 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.web;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.mitre.jwt.signer.service.JWTSigningAndValidationService;
|
||||
import org.mitre.oauth2.model.AuthenticationHolderEntity;
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||
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.oauth2.service.SystemScopeService;
|
||||
import org.mitre.oauth2.web.AuthenticationUtilities;
|
||||
import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
|
||||
import org.mitre.openid.connect.service.OIDCTokenService;
|
||||
import org.mitre.openid.connect.view.HttpCodeView;
|
||||
import org.mitre.openid.connect.view.JsonEntityView;
|
||||
import org.mitre.openid.connect.view.JsonErrorView;
|
||||
import org.mitre.uma.model.Claim;
|
||||
import org.mitre.uma.model.PermissionTicket;
|
||||
import org.mitre.uma.model.ResourceSet;
|
||||
import org.mitre.uma.service.ClaimsProcessingService;
|
||||
import org.mitre.uma.service.PermissionService;
|
||||
import org.mitre.uma.service.UmaTokenService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.nimbusds.jose.JWSAlgorithm;
|
||||
import com.nimbusds.jose.JWSHeader;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.SignedJWT;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/" + AuthorizationRequestEndpoint.URL)
|
||||
public class AuthorizationRequestEndpoint {
|
||||
// Logger for this class
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuthorizationRequestEndpoint.class);
|
||||
|
||||
public static final String RPT = "rpt";
|
||||
public static final String TICKET = "ticket";
|
||||
public static final String URL = "authz_request";
|
||||
|
||||
@Autowired
|
||||
private PermissionService permissionService;
|
||||
|
||||
@Autowired
|
||||
private OAuth2TokenEntityService tokenService;
|
||||
|
||||
@Autowired
|
||||
private OIDCTokenService oidcTokenService;
|
||||
|
||||
@Autowired
|
||||
private WebResponseExceptionTranslator providerExceptionHandler;
|
||||
|
||||
@Autowired
|
||||
private ClaimsProcessingService claimsProcessingService;
|
||||
|
||||
@Autowired
|
||||
private UmaTokenService umaTokenService;
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
|
||||
public String authorizationRequest(@RequestBody String jsonString, Model m, Authentication auth) {
|
||||
|
||||
AuthenticationUtilities.ensureOAuthScope(auth, SystemScopeService.UMA_AUTHORIZATION_SCOPE);
|
||||
|
||||
JsonParser parser = new JsonParser();
|
||||
JsonElement e = parser.parse(jsonString);
|
||||
|
||||
if (e.isJsonObject()) {
|
||||
JsonObject o = e.getAsJsonObject();
|
||||
|
||||
if (o.has(TICKET)) {
|
||||
|
||||
OAuth2AccessTokenEntity incomingRpt = null;
|
||||
if (o.has(RPT)) {
|
||||
String rptValue = o.get(RPT).getAsString();
|
||||
incomingRpt = tokenService.readAccessToken(rptValue);
|
||||
}
|
||||
|
||||
String ticketValue = o.get(TICKET).getAsString();
|
||||
|
||||
PermissionTicket ticket = permissionService.getByTicket(ticketValue);
|
||||
|
||||
if (ticket != null) {
|
||||
// found the ticket, see if it's any good
|
||||
|
||||
ResourceSet rs = ticket.getPermission().getResourceSet();
|
||||
|
||||
if (rs.getClaimsRequired() == null || rs.getClaimsRequired().isEmpty()) {
|
||||
// the required claims are empty, this resource has no way to be authorized
|
||||
|
||||
m.addAttribute(JsonErrorView.ERROR, "not_authorized");
|
||||
m.addAttribute(JsonErrorView.ERROR_MESSAGE, "This resource set can not be accessed.");
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN);
|
||||
return JsonErrorView.VIEWNAME;
|
||||
} else {
|
||||
// claims weren't empty or missing, we need to check against what we have
|
||||
|
||||
Collection<Claim> claimsUnmatched = claimsProcessingService.claimsAreSatisfied(rs.getClaimsRequired(), ticket.getClaimsSupplied());
|
||||
|
||||
if (claimsUnmatched.isEmpty()) {
|
||||
// if the unmatched claims come back empty, by function contract that means we're happy and can issue a token
|
||||
|
||||
OAuth2Authentication o2auth = (OAuth2Authentication) auth;
|
||||
|
||||
OAuth2AccessTokenEntity token = umaTokenService.createRequestingPartyToken(o2auth, ticket);
|
||||
|
||||
// if we have an inbound RPT, throw it out because we're replacing it
|
||||
if (incomingRpt != null) {
|
||||
tokenService.revokeAccessToken(incomingRpt);
|
||||
}
|
||||
|
||||
Map<String, String> entity = ImmutableMap.of("rpt", token.getValue());
|
||||
|
||||
m.addAttribute(JsonEntityView.ENTITY, entity);
|
||||
|
||||
return JsonEntityView.VIEWNAME;
|
||||
|
||||
} else {
|
||||
|
||||
// if we got here, the claim didn't match, forward the user to the claim gathering endpoint
|
||||
JsonObject entity = new JsonObject();
|
||||
|
||||
entity.addProperty(JsonErrorView.ERROR, "need_info");
|
||||
JsonObject details = new JsonObject();
|
||||
|
||||
JsonObject rpClaims = new JsonObject();
|
||||
rpClaims.addProperty("redirect_user", true);
|
||||
rpClaims.addProperty("ticket", ticketValue);
|
||||
JsonArray req = new JsonArray();
|
||||
for (Claim claim : claimsUnmatched) {
|
||||
JsonObject c = new JsonObject();
|
||||
c.addProperty("name", claim.getName());
|
||||
c.addProperty("friendly_name", claim.getFriendlyName());
|
||||
c.addProperty("claim_type", claim.getClaimType());
|
||||
JsonArray f = new JsonArray();
|
||||
for (String format : claim.getClaimTokenFormat()) {
|
||||
f.add(new JsonPrimitive(format));
|
||||
}
|
||||
c.add("claim_token_format", f);
|
||||
JsonArray i = new JsonArray();
|
||||
for (String issuer : claim.getIssuer()) {
|
||||
i.add(new JsonPrimitive(issuer));
|
||||
}
|
||||
c.add("issuer", i);
|
||||
req.add(c);
|
||||
}
|
||||
rpClaims.add("required_claims", req);
|
||||
details.add("requesting_party_claims", rpClaims);
|
||||
entity.add("error_details", details);
|
||||
|
||||
m.addAttribute(JsonEntityView.ENTITY, entity);
|
||||
return JsonEntityView.VIEWNAME;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} else {
|
||||
// ticket wasn't found, return an error
|
||||
m.addAttribute(HttpStatus.BAD_REQUEST);
|
||||
m.addAttribute(JsonErrorView.ERROR, "invalid_ticket");
|
||||
return JsonErrorView.VIEWNAME;
|
||||
}
|
||||
|
||||
} else {
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
|
||||
m.addAttribute(JsonErrorView.ERROR_MESSAGE, "Missing JSON elements.");
|
||||
return JsonErrorView.VIEWNAME;
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
|
||||
m.addAttribute(JsonErrorView.ERROR_MESSAGE, "Malformed JSON request.");
|
||||
return JsonErrorView.VIEWNAME;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ExceptionHandler(OAuth2Exception.class)
|
||||
public ResponseEntity<OAuth2Exception> handleException(Exception e) throws Exception {
|
||||
logger.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
|
||||
return providerExceptionHandler.translate(e);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.web;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mitre.oauth2.service.SystemScopeService;
|
||||
import org.mitre.openid.connect.view.HttpCodeView;
|
||||
import org.mitre.openid.connect.view.JsonEntityView;
|
||||
import org.mitre.openid.connect.view.JsonErrorView;
|
||||
import org.mitre.openid.connect.web.RootController;
|
||||
import org.mitre.uma.model.Claim;
|
||||
import org.mitre.uma.model.ResourceSet;
|
||||
import org.mitre.uma.service.ResourceSetService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import static org.mitre.oauth2.web.AuthenticationUtilities.ensureOAuthScope;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/" + ClaimsAPI.URL)
|
||||
@PreAuthorize("hasRole('ROLE_USER')")
|
||||
public class ClaimsAPI {
|
||||
// Logger for this class
|
||||
private static final Logger logger = LoggerFactory.getLogger(ClaimsAPI.class);
|
||||
|
||||
public static final String URL = RootController.API_URL + "/claims";
|
||||
|
||||
@Autowired
|
||||
private ResourceSetService resourceSetService;
|
||||
|
||||
@RequestMapping(value = "", method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
|
||||
public String getResourceSetsForCurrentUser(Model m, Authentication auth) {
|
||||
|
||||
Collection<ResourceSet> resourceSets = resourceSetService.getAllForOwner(auth.getName());
|
||||
|
||||
m.addAttribute(JsonEntityView.ENTITY, resourceSets);
|
||||
|
||||
return JsonEntityView.VIEWNAME;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/{rsid}", method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
|
||||
public String getClaimsForResourceSet(@PathVariable (value = "rsid") Long rsid, Model m, Authentication auth) {
|
||||
|
||||
ResourceSet rs = resourceSetService.getById(rsid);
|
||||
|
||||
if (rs == null) {
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
|
||||
return HttpCodeView.VIEWNAME;
|
||||
}
|
||||
|
||||
if (!rs.getOwner().equals(auth.getName())) {
|
||||
// authenticated user didn't match the owner of the resource set
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN);
|
||||
return HttpCodeView.VIEWNAME;
|
||||
}
|
||||
|
||||
m.addAttribute(JsonEntityView.ENTITY, rs.getClaimsRequired());
|
||||
|
||||
return JsonEntityView.VIEWNAME;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/{rsid}", method = RequestMethod.PUT, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
|
||||
public String setClaimsForResourceSet(@PathVariable (value = "rsid") Long rsid, @RequestBody String jsonString, Model m, Authentication auth) {
|
||||
|
||||
ResourceSet rs = resourceSetService.getById(rsid);
|
||||
|
||||
if (rs == null) {
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
|
||||
return HttpCodeView.VIEWNAME;
|
||||
}
|
||||
|
||||
if (!rs.getOwner().equals(auth.getName())) {
|
||||
// authenticated user didn't match the owner of the resource set
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN);
|
||||
return HttpCodeView.VIEWNAME;
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
Set<Claim> claims = (new Gson()).fromJson(jsonString, new TypeToken<Set<Claim>>() {}.getType());
|
||||
|
||||
rs.setClaimsRequired(claims);
|
||||
|
||||
resourceSetService.update(rs, rs);
|
||||
|
||||
m.addAttribute(JsonEntityView.ENTITY, rs.getClaimsRequired());
|
||||
|
||||
return JsonEntityView.VIEWNAME;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/{rsid}", method = RequestMethod.DELETE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
|
||||
public String deleteResourceSet(@PathVariable ("rsid") Long id, Model m, Authentication auth) {
|
||||
|
||||
ResourceSet rs = resourceSetService.getById(id);
|
||||
|
||||
if (rs == null) {
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
|
||||
m.addAttribute(JsonErrorView.ERROR, "not_found");
|
||||
return JsonErrorView.VIEWNAME;
|
||||
} else {
|
||||
if (!auth.getName().equals(rs.getOwner())) {
|
||||
|
||||
logger.warn("Unauthorized resource set request from bad user; expected " + rs.getOwner() + " got " + auth.getName());
|
||||
|
||||
// it wasn't issued to this user
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN);
|
||||
return JsonErrorView.VIEWNAME;
|
||||
} else {
|
||||
|
||||
resourceSetService.remove(rs);
|
||||
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.NO_CONTENT);
|
||||
return HttpCodeView.VIEWNAME;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.web;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
import org.mitre.oauth2.service.ClientDetailsEntityService;
|
||||
import org.mitre.openid.connect.model.OIDCAuthenticationToken;
|
||||
import org.mitre.openid.connect.model.UserInfo;
|
||||
import org.mitre.openid.connect.view.HttpCodeView;
|
||||
import org.mitre.openid.connect.view.JsonErrorView;
|
||||
import org.mitre.uma.model.Claim;
|
||||
import org.mitre.uma.model.PermissionTicket;
|
||||
import org.mitre.uma.service.PermissionService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
*
|
||||
* Collect claims interactively from the end user.
|
||||
*
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Controller
|
||||
@PreAuthorize("hasRole('ROLE_EXTERNAL_USER')")
|
||||
@RequestMapping("/" + ClaimsCollectionEndpoint.URL)
|
||||
public class ClaimsCollectionEndpoint {
|
||||
// Logger for this class
|
||||
private static final Logger logger = LoggerFactory.getLogger(ClaimsCollectionEndpoint.class);
|
||||
|
||||
public static final String URL = "rqp_claims";
|
||||
|
||||
@Autowired
|
||||
private ClientDetailsEntityService clientService;
|
||||
|
||||
@Autowired
|
||||
private PermissionService permissionService;
|
||||
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET)
|
||||
public String collectClaims(@RequestParam("client_id") String clientId, @RequestParam(value = "redirect_uri", required = false) String redirectUri,
|
||||
@RequestParam("ticket") String ticketValue, @RequestParam(value = "state", required = false) String state,
|
||||
Model m, OIDCAuthenticationToken auth) {
|
||||
|
||||
|
||||
ClientDetailsEntity client = clientService.loadClientByClientId(clientId);
|
||||
|
||||
PermissionTicket ticket = permissionService.getByTicket(ticketValue);
|
||||
|
||||
if (client == null || ticket == null) {
|
||||
logger.info("Client or ticket not found: " + clientId + " :: " + ticketValue);
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
|
||||
return HttpCodeView.VIEWNAME;
|
||||
}
|
||||
|
||||
// we've got a client and ticket, let's attach the claims that we have from the token and userinfo
|
||||
|
||||
// subject
|
||||
Set<Claim> claimsSupplied = Sets.newHashSet(ticket.getClaimsSupplied());
|
||||
|
||||
String issuer = auth.getIssuer();
|
||||
UserInfo userInfo = auth.getUserInfo();
|
||||
|
||||
claimsSupplied.add(mkClaim(issuer, "sub", auth.getSub()));
|
||||
claimsSupplied.add(mkClaim(issuer, "email", userInfo.getEmail()));
|
||||
claimsSupplied.add(mkClaim(issuer, "phone_number", auth.getUserInfo().getPhoneNumber()));
|
||||
claimsSupplied.add(mkClaim(issuer, "preferred_username", auth.getUserInfo().getPreferredUsername()));
|
||||
claimsSupplied.add(mkClaim(issuer, "profile", auth.getUserInfo().getProfile()));
|
||||
|
||||
ticket.setClaimsSupplied(claimsSupplied);
|
||||
|
||||
PermissionTicket updatedTicket = permissionService.updateTicket(ticket);
|
||||
|
||||
if (Strings.isNullOrEmpty(redirectUri)) {
|
||||
if (client.getRedirectUris().size() == 1) {
|
||||
redirectUri = client.getRedirectUris().iterator().next(); // get the first (and only) redirect URI to use here
|
||||
logger.info("No redirect URI passed in, using registered value: " + redirectUri);
|
||||
}
|
||||
}
|
||||
|
||||
UriComponentsBuilder template = UriComponentsBuilder.fromUriString(redirectUri);
|
||||
template.queryParam("authorization_state", "claims_submitted");
|
||||
if (!Strings.isNullOrEmpty(state)) {
|
||||
template.queryParam("state", state);
|
||||
}
|
||||
|
||||
String uriString = template.toUriString();
|
||||
logger.info("Redirecting to " + uriString);
|
||||
|
||||
return "redirect:" + uriString;
|
||||
}
|
||||
|
||||
|
||||
private Claim mkClaim(String issuer, String name, String value) {
|
||||
Claim c = new Claim();
|
||||
c.setIssuer(Sets.newHashSet(issuer));
|
||||
c.setName(name);
|
||||
c.setValue(value);
|
||||
return c;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.web;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.mitre.oauth2.web.AuthenticationUtilities.ensureOAuthScope;
|
||||
import static org.mitre.util.JsonUtils.getAsLong;
|
||||
import static org.mitre.util.JsonUtils.getAsStringSet;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.mitre.oauth2.model.SystemScope;
|
||||
import org.mitre.oauth2.service.SystemScopeService;
|
||||
import org.mitre.openid.connect.view.JsonEntityView;
|
||||
import org.mitre.openid.connect.view.JsonErrorView;
|
||||
import org.mitre.uma.model.PermissionTicket;
|
||||
import org.mitre.uma.model.ResourceSet;
|
||||
import org.mitre.uma.service.PermissionService;
|
||||
import org.mitre.uma.service.ResourceSetService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
|
||||
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/" + PermissionRegistrationEndpoint.URL)
|
||||
@PreAuthorize("hasRole('ROLE_USER')")
|
||||
public class PermissionRegistrationEndpoint {
|
||||
// Logger for this class
|
||||
private static final Logger logger = LoggerFactory.getLogger(PermissionRegistrationEndpoint.class);
|
||||
|
||||
public static final String URL = "permission";
|
||||
|
||||
@Autowired
|
||||
private PermissionService permissionService;
|
||||
|
||||
@Autowired
|
||||
private ResourceSetService resourceSetService;
|
||||
|
||||
@Autowired
|
||||
private SystemScopeService scopeService;
|
||||
|
||||
@Autowired
|
||||
private WebResponseExceptionTranslator providerExceptionHandler;
|
||||
|
||||
private JsonParser parser = new JsonParser();
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
|
||||
public String getPermissionTicket(@RequestBody String jsonString, Model m, Authentication auth) {
|
||||
|
||||
ensureOAuthScope(auth, SystemScopeService.UMA_PROTECTION_SCOPE);
|
||||
|
||||
try {
|
||||
|
||||
// parse the permission request
|
||||
|
||||
JsonElement el = parser.parse(jsonString);
|
||||
if (el.isJsonObject()) {
|
||||
JsonObject o = el.getAsJsonObject();
|
||||
|
||||
Long rsid = getAsLong(o, "resource_set_id");
|
||||
Set<String> scopes = getAsStringSet(o, "scopes");
|
||||
|
||||
if (rsid == null || scopes == null || scopes.isEmpty()){
|
||||
// missing information
|
||||
m.addAttribute("code", HttpStatus.BAD_REQUEST);
|
||||
m.addAttribute("errorMessage", "Missing required component of resource registration request.");
|
||||
return JsonErrorView.VIEWNAME;
|
||||
}
|
||||
|
||||
// trim any restricted scopes
|
||||
Set<SystemScope> scopesRequested = scopeService.fromStrings(scopes);
|
||||
scopesRequested = scopeService.removeRestrictedAndReservedScopes(scopesRequested);
|
||||
scopes = scopeService.toStrings(scopesRequested);
|
||||
|
||||
ResourceSet resourceSet = resourceSetService.getById(rsid);
|
||||
|
||||
// requested resource set doesn't exist
|
||||
if (resourceSet == null) {
|
||||
m.addAttribute("code", HttpStatus.NOT_FOUND);
|
||||
m.addAttribute("errorMessage", "Requested resource set not found: " + rsid);
|
||||
return JsonErrorView.VIEWNAME;
|
||||
}
|
||||
|
||||
// authorized user of the token doesn't match owner of the resource set
|
||||
if (!resourceSet.getOwner().equals(auth.getName())) {
|
||||
m.addAttribute("code", HttpStatus.FORBIDDEN);
|
||||
m.addAttribute("errorMessage", "Party requesting permission is not owner of resource set, expected " + resourceSet.getOwner() + " got " + auth.getName());
|
||||
return JsonErrorView.VIEWNAME;
|
||||
}
|
||||
|
||||
// create the permission
|
||||
PermissionTicket permission = permissionService.createTicket(resourceSet, scopes);
|
||||
|
||||
if (permission != null) {
|
||||
// we've created the permission, return the ticket
|
||||
JsonObject out = new JsonObject();
|
||||
out.addProperty("ticket", permission.getTicket());
|
||||
m.addAttribute("entity", out);
|
||||
|
||||
m.addAttribute("code", HttpStatus.CREATED);
|
||||
|
||||
return JsonEntityView.VIEWNAME;
|
||||
} else {
|
||||
// there was a failure creating the permission object
|
||||
|
||||
m.addAttribute("code", HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
m.addAttribute("errorMessage", "Unable to save permission and generate ticket.");
|
||||
|
||||
return JsonErrorView.VIEWNAME;
|
||||
}
|
||||
|
||||
} else {
|
||||
// malformed request
|
||||
m.addAttribute("code", HttpStatus.BAD_REQUEST);
|
||||
m.addAttribute("errorMessage", "Malformed JSON request.");
|
||||
return JsonErrorView.VIEWNAME;
|
||||
}
|
||||
} catch (JsonParseException e) {
|
||||
// malformed request
|
||||
m.addAttribute("code", HttpStatus.BAD_REQUEST);
|
||||
m.addAttribute("errorMessage", "Malformed JSON request.");
|
||||
return JsonErrorView.VIEWNAME;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ExceptionHandler(OAuth2Exception.class)
|
||||
public ResponseEntity<OAuth2Exception> handleException(Exception e) throws Exception {
|
||||
logger.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
|
||||
return providerExceptionHandler.translate(e);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,333 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.web;
|
||||
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mitre.oauth2.model.SystemScope;
|
||||
import org.mitre.oauth2.service.SystemScopeService;
|
||||
import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
|
||||
import org.mitre.openid.connect.view.HttpCodeView;
|
||||
import org.mitre.openid.connect.view.JsonEntityView;
|
||||
import org.mitre.openid.connect.view.JsonErrorView;
|
||||
import org.mitre.uma.model.ResourceSet;
|
||||
import org.mitre.uma.service.ResourceSetService;
|
||||
import org.mitre.uma.view.ResourceSetEntityAbbreviatedView;
|
||||
import org.mitre.uma.view.ResourceSetEntityView;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import static org.mitre.oauth2.web.AuthenticationUtilities.ensureOAuthScope;
|
||||
import static org.mitre.util.JsonUtils.getAsLong;
|
||||
import static org.mitre.util.JsonUtils.getAsString;
|
||||
import static org.mitre.util.JsonUtils.getAsStringSet;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/" + ResourceSetRegistrationEndpoint.URL)
|
||||
@PreAuthorize("hasRole('ROLE_USER')")
|
||||
public class ResourceSetRegistrationEndpoint {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ResourceSetRegistrationEndpoint.class);
|
||||
|
||||
public static final String DISCOVERY_URL = "resource_set";
|
||||
public static final String URL = DISCOVERY_URL + "/resource_set";
|
||||
|
||||
@Autowired
|
||||
private ResourceSetService resourceSetService;
|
||||
|
||||
@Autowired
|
||||
private ConfigurationPropertiesBean config;
|
||||
|
||||
@Autowired
|
||||
private SystemScopeService scopeService;
|
||||
|
||||
@Autowired
|
||||
private WebResponseExceptionTranslator providerExceptionHandler;
|
||||
|
||||
|
||||
private JsonParser parser = new JsonParser();
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST, produces = MimeTypeUtils.APPLICATION_JSON_VALUE, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE)
|
||||
public String createResourceSet(@RequestBody String jsonString, Model m, Authentication auth) {
|
||||
ensureOAuthScope(auth, SystemScopeService.UMA_PROTECTION_SCOPE);
|
||||
|
||||
ResourceSet rs = parseResourceSet(jsonString);
|
||||
|
||||
if (rs == null) { // there was no resource set in the body
|
||||
logger.warn("Resource set registration missing body.");
|
||||
|
||||
m.addAttribute("code", HttpStatus.BAD_REQUEST);
|
||||
m.addAttribute("error_description", "Resource request was missing body.");
|
||||
return JsonErrorView.VIEWNAME;
|
||||
}
|
||||
|
||||
if (auth instanceof OAuth2Authentication) {
|
||||
// if it's an OAuth mediated call, it's on behalf of a client, so store that
|
||||
OAuth2Authentication o2a = (OAuth2Authentication) auth;
|
||||
rs.setClientId(o2a.getOAuth2Request().getClientId());
|
||||
rs.setOwner(auth.getName()); // the username is going to be in the auth object
|
||||
} else {
|
||||
// this one shouldn't be called if it's not OAuth
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
|
||||
m.addAttribute(JsonErrorView.ERROR_MESSAGE, "This call must be made with an OAuth token");
|
||||
return JsonErrorView.VIEWNAME;
|
||||
}
|
||||
|
||||
rs = validateScopes(rs);
|
||||
|
||||
if (Strings.isNullOrEmpty(rs.getName()) // there was no name (required)
|
||||
|| rs.getScopes() == null // there were no scopes (required)
|
||||
) {
|
||||
|
||||
logger.warn("Resource set registration missing one or more required fields.");
|
||||
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
|
||||
m.addAttribute(JsonErrorView.ERROR_MESSAGE, "Resource request was missing one or more required fields.");
|
||||
return JsonErrorView.VIEWNAME;
|
||||
}
|
||||
|
||||
ResourceSet saved = resourceSetService.saveNew(rs);
|
||||
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.CREATED);
|
||||
m.addAttribute(JsonEntityView.ENTITY, saved);
|
||||
m.addAttribute(ResourceSetEntityAbbreviatedView.LOCATION, config.getIssuer() + URL + "/" + rs.getId());
|
||||
|
||||
return ResourceSetEntityAbbreviatedView.VIEWNAME;
|
||||
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
|
||||
public String readResourceSet(@PathVariable ("id") Long id, Model m, Authentication auth) {
|
||||
ensureOAuthScope(auth, SystemScopeService.UMA_PROTECTION_SCOPE);
|
||||
|
||||
ResourceSet rs = resourceSetService.getById(id);
|
||||
|
||||
if (rs == null) {
|
||||
m.addAttribute("code", HttpStatus.NOT_FOUND);
|
||||
m.addAttribute("error", "not_found");
|
||||
return JsonErrorView.VIEWNAME;
|
||||
} else {
|
||||
|
||||
rs = validateScopes(rs);
|
||||
|
||||
if (!auth.getName().equals(rs.getOwner())) {
|
||||
|
||||
logger.warn("Unauthorized resource set request from wrong user; expected " + rs.getOwner() + " got " + auth.getName());
|
||||
|
||||
// it wasn't issued to this user
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN);
|
||||
return JsonErrorView.VIEWNAME;
|
||||
} else {
|
||||
m.addAttribute(JsonEntityView.ENTITY, rs);
|
||||
return ResourceSetEntityView.VIEWNAME;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/{id}", method = RequestMethod.PUT, consumes = MimeTypeUtils.APPLICATION_JSON_VALUE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
|
||||
public String updateResourceSet(@PathVariable ("id") Long id, @RequestBody String jsonString, Model m, Authentication auth) {
|
||||
ensureOAuthScope(auth, SystemScopeService.UMA_PROTECTION_SCOPE);
|
||||
|
||||
ResourceSet newRs = parseResourceSet(jsonString);
|
||||
|
||||
if (newRs == null // there was no resource set in the body
|
||||
|| Strings.isNullOrEmpty(newRs.getName()) // there was no name (required)
|
||||
|| newRs.getScopes() == null // there were no scopes (required)
|
||||
|| newRs.getId() == null || !newRs.getId().equals(id) // the IDs didn't match
|
||||
) {
|
||||
|
||||
logger.warn("Resource set registration missing one or more required fields.");
|
||||
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
|
||||
m.addAttribute(JsonErrorView.ERROR_MESSAGE, "Resource request was missing one or more required fields.");
|
||||
return JsonErrorView.VIEWNAME;
|
||||
}
|
||||
|
||||
ResourceSet rs = resourceSetService.getById(id);
|
||||
|
||||
if (rs == null) {
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
|
||||
m.addAttribute(JsonErrorView.ERROR, "not_found");
|
||||
return JsonErrorView.VIEWNAME;
|
||||
} else {
|
||||
if (!auth.getName().equals(rs.getOwner())) {
|
||||
|
||||
logger.warn("Unauthorized resource set request from bad user; expected " + rs.getOwner() + " got " + auth.getName());
|
||||
|
||||
// it wasn't issued to this user
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN);
|
||||
return JsonErrorView.VIEWNAME;
|
||||
} else {
|
||||
|
||||
ResourceSet saved = resourceSetService.update(rs, newRs);
|
||||
|
||||
m.addAttribute(JsonEntityView.ENTITY, saved);
|
||||
m.addAttribute(ResourceSetEntityAbbreviatedView.LOCATION, config.getIssuer() + URL + "/" + rs.getId());
|
||||
return ResourceSetEntityAbbreviatedView.VIEWNAME;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
|
||||
public String deleteResourceSet(@PathVariable ("id") Long id, Model m, Authentication auth) {
|
||||
ensureOAuthScope(auth, SystemScopeService.UMA_PROTECTION_SCOPE);
|
||||
|
||||
ResourceSet rs = resourceSetService.getById(id);
|
||||
|
||||
if (rs == null) {
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
|
||||
m.addAttribute(JsonErrorView.ERROR, "not_found");
|
||||
return JsonErrorView.VIEWNAME;
|
||||
} else {
|
||||
if (!auth.getName().equals(rs.getOwner())) {
|
||||
|
||||
logger.warn("Unauthorized resource set request from bad user; expected " + rs.getOwner() + " got " + auth.getName());
|
||||
|
||||
// it wasn't issued to this user
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN);
|
||||
return JsonErrorView.VIEWNAME;
|
||||
} else if (auth instanceof OAuth2Authentication &&
|
||||
!((OAuth2Authentication)auth).getOAuth2Request().getClientId().equals(rs.getClientId())){
|
||||
|
||||
logger.warn("Unauthorized resource set request from bad client; expected " + rs.getClientId() + " got " + ((OAuth2Authentication)auth).getOAuth2Request().getClientId());
|
||||
|
||||
// it wasn't issued to this client
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN);
|
||||
return JsonErrorView.VIEWNAME;
|
||||
} else {
|
||||
|
||||
// user and client matched
|
||||
resourceSetService.remove(rs);
|
||||
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.NO_CONTENT);
|
||||
return HttpCodeView.VIEWNAME;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
|
||||
public String listResourceSets(Model m, Authentication auth) {
|
||||
ensureOAuthScope(auth, SystemScopeService.UMA_PROTECTION_SCOPE);
|
||||
|
||||
String owner = auth.getName();
|
||||
|
||||
Collection<ResourceSet> resourceSets = Collections.emptySet();
|
||||
if (auth instanceof OAuth2Authentication) {
|
||||
// if it's an OAuth mediated call, it's on behalf of a client, so look that up too
|
||||
OAuth2Authentication o2a = (OAuth2Authentication) auth;
|
||||
resourceSets = resourceSetService.getAllForOwnerAndClient(owner, o2a.getOAuth2Request().getClientId());
|
||||
} else {
|
||||
// otherwise get everything for the current user
|
||||
resourceSets = resourceSetService.getAllForOwner(owner);
|
||||
}
|
||||
|
||||
// build the entity here and send to the display
|
||||
|
||||
Set<String> ids = new HashSet<>();
|
||||
for (ResourceSet resourceSet : resourceSets) {
|
||||
ids.add(resourceSet.getId().toString()); // add them all as strings so that gson renders them properly
|
||||
}
|
||||
|
||||
m.addAttribute(JsonEntityView.ENTITY, ids);
|
||||
return JsonEntityView.VIEWNAME;
|
||||
}
|
||||
|
||||
private ResourceSet parseResourceSet(String jsonString) {
|
||||
|
||||
try {
|
||||
JsonElement el = parser.parse(jsonString);
|
||||
|
||||
if (el.isJsonObject()) {
|
||||
JsonObject o = el.getAsJsonObject();
|
||||
|
||||
ResourceSet rs = new ResourceSet();
|
||||
rs.setId(getAsLong(o, "_id"));
|
||||
rs.setName(getAsString(o, "name"));
|
||||
rs.setIconUri(getAsString(o, "icon_uri"));
|
||||
rs.setType(getAsString(o, "type"));
|
||||
rs.setScopes(getAsStringSet(o, "scopes"));
|
||||
rs.setUri(getAsString(o, "uri"));
|
||||
|
||||
return rs;
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
} catch (JsonParseException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Make sure the resource set doesn't have any restricted or reserved scopes.
|
||||
*
|
||||
* @param rs
|
||||
*/
|
||||
private ResourceSet validateScopes(ResourceSet rs) {
|
||||
// scopes that the client is asking for
|
||||
Set<SystemScope> requestedScopes = scopeService.fromStrings(rs.getScopes());
|
||||
|
||||
// the scopes that the resource set can have must be a subset of the dynamically allowed scopes
|
||||
Set<SystemScope> allowedScopes = scopeService.removeRestrictedAndReservedScopes(requestedScopes);
|
||||
|
||||
rs.setScopes(scopeService.toStrings(allowedScopes));
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
@ExceptionHandler(OAuth2Exception.class)
|
||||
public ResponseEntity<OAuth2Exception> handleException(Exception e) throws Exception {
|
||||
logger.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
|
||||
return providerExceptionHandler.translate(e);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.web;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mitre.oauth2.web.IntrospectionEndpoint;
|
||||
import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
|
||||
import org.mitre.openid.connect.view.JsonEntityView;
|
||||
import org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Controller
|
||||
public class UmaDiscoveryEndpoint {
|
||||
|
||||
@Autowired
|
||||
private ConfigurationPropertiesBean config;
|
||||
|
||||
@RequestMapping(".well-known/uma-configuration")
|
||||
public String umaConfiguration(Model model) {
|
||||
|
||||
Map<String, Object> m = new HashMap<String, Object>();
|
||||
|
||||
String issuer = config.getIssuer();
|
||||
ImmutableSet<String> tokenProfiles = ImmutableSet.of("bearer");
|
||||
ArrayList<String> grantTypes = Lists.newArrayList("authorization_code", "implicit", "urn:ietf:params:oauth:grant-type:jwt-bearer", "client_credentials", "urn:ietf:params:oauth:grant_type:redelegate");
|
||||
|
||||
m.put("version", "1.0");
|
||||
m.put("issuer", issuer);
|
||||
m.put("pat_profiles_supported", tokenProfiles);
|
||||
m.put("aat_profiles_supported", tokenProfiles);
|
||||
m.put("rpt_profiles_supported", tokenProfiles);
|
||||
m.put("pat_grant_types_supported", grantTypes);
|
||||
m.put("aat_grant_types_supported", grantTypes);
|
||||
m.put("claim_token_profiles_supported", ImmutableSet.of());
|
||||
m.put("uma_profiles_supported", ImmutableSet.of());
|
||||
m.put("dynamic_client_endpoint", issuer + DynamicClientRegistrationEndpoint.URL);
|
||||
m.put("token_endpoint", issuer + "token");
|
||||
m.put("authorization_endpoint", issuer + "authorize");
|
||||
m.put("requesting_party_claims_endpoint", issuer + ClaimsCollectionEndpoint.URL);
|
||||
m.put("introspection_endpoint", issuer + IntrospectionEndpoint.URL);
|
||||
m.put("resource_set_registration_endpoint", issuer + ResourceSetRegistrationEndpoint.DISCOVERY_URL);
|
||||
m.put("permission_registration_endpoint", issuer + PermissionRegistrationEndpoint.URL);
|
||||
m.put("rpt_endpoint", issuer + AuthorizationRequestEndpoint.URL);
|
||||
|
||||
|
||||
|
||||
model.addAttribute("entity", m);
|
||||
return JsonEntityView.VIEWNAME;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.web;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.mitre.openid.connect.client.model.IssuerServiceResponse;
|
||||
import org.mitre.openid.connect.client.service.impl.WebfingerIssuerService;
|
||||
import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
|
||||
import org.mitre.openid.connect.model.UserInfo;
|
||||
import org.mitre.openid.connect.service.UserInfoService;
|
||||
import org.mitre.openid.connect.view.HttpCodeView;
|
||||
import org.mitre.openid.connect.view.JsonEntityView;
|
||||
import org.mitre.openid.connect.view.JsonErrorView;
|
||||
import org.mitre.openid.connect.web.RootController;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/" + UserClaimSearchHelper.URL)
|
||||
@PreAuthorize("hasRole('ROLE_USER')")
|
||||
public class UserClaimSearchHelper {
|
||||
|
||||
public static final String URL = RootController.API_URL + "/emailsearch";
|
||||
|
||||
private WebfingerIssuerService webfingerIssuerService = new WebfingerIssuerService();
|
||||
|
||||
@Autowired
|
||||
private UserInfoService userInfoService;
|
||||
|
||||
@Autowired
|
||||
private ConfigurationPropertiesBean config;
|
||||
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
|
||||
public String search(@RequestParam(value = "identifier") String email, Model m, Authentication auth, HttpServletRequest req) {
|
||||
|
||||
// check locally first
|
||||
UserInfo localUser = userInfoService.getByEmailAddress(email);
|
||||
|
||||
if (localUser != null) {
|
||||
Map<String, Object> entity = new HashMap<>();
|
||||
entity.put("issuer", ImmutableSet.of(config.getIssuer()));
|
||||
entity.put("name", "email");
|
||||
entity.put("value", localUser.getEmail());
|
||||
|
||||
m.addAttribute(JsonEntityView.ENTITY, entity);
|
||||
return JsonEntityView.VIEWNAME;
|
||||
}
|
||||
|
||||
|
||||
// otherwise do a webfinger lookup
|
||||
IssuerServiceResponse resp = webfingerIssuerService.getIssuer(req);
|
||||
|
||||
if (resp != null && resp.getIssuer() != null) {
|
||||
// we found an issuer, return that
|
||||
Map<String, Object> entity = new HashMap<>();
|
||||
entity.put("issuer", ImmutableSet.of(resp.getIssuer()));
|
||||
entity.put("name", "email");
|
||||
entity.put("value", email);
|
||||
|
||||
m.addAttribute(JsonEntityView.ENTITY, entity);
|
||||
return JsonEntityView.VIEWNAME;
|
||||
} else {
|
||||
m.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
|
||||
return JsonErrorView.VIEWNAME;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.service.impl;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mitre.oauth2.service.SystemScopeService;
|
||||
import org.mitre.uma.model.PermissionTicket;
|
||||
import org.mitre.uma.model.ResourceSet;
|
||||
import org.mitre.uma.repository.PermissionRepository;
|
||||
import org.mockito.AdditionalAnswers;
|
||||
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 org.springframework.security.oauth2.common.exceptions.InsufficientScopeException;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
|
||||
import static org.mockito.Matchers.anySetOf;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class TestDefaultPermissionService {
|
||||
|
||||
@Mock
|
||||
private PermissionRepository permissionRepository;
|
||||
|
||||
@Mock
|
||||
private SystemScopeService scopeService;
|
||||
|
||||
@InjectMocks
|
||||
private DefaultPermissionService permissionService;
|
||||
|
||||
private Set<String> scopes1 = ImmutableSet.of("foo", "bar", "baz");
|
||||
private Set<String> scopes2 = ImmutableSet.of("alpha", "beta", "betest");
|
||||
|
||||
private ResourceSet rs1;
|
||||
private ResourceSet rs2;
|
||||
|
||||
private String rs1Name = "resource set 1";
|
||||
private String rs1Owner = "resource set owner 1";
|
||||
private Long rs1Id = 1L;
|
||||
|
||||
private String rs2Name = "resource set 2";
|
||||
private String rs2Owner = "resource set owner 2";
|
||||
private Long rs2Id = 2L;
|
||||
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
rs1 = new ResourceSet();
|
||||
rs1.setName(rs1Name);
|
||||
rs1.setOwner(rs1Owner);
|
||||
rs1.setId(rs1Id );
|
||||
rs1.setScopes(scopes1);
|
||||
|
||||
rs2 = new ResourceSet();
|
||||
rs2.setName(rs2Name);
|
||||
rs2.setOwner(rs2Owner);
|
||||
rs2.setId(rs2Id);
|
||||
rs2.setScopes(scopes2);
|
||||
|
||||
// have the repository just pass the argument through
|
||||
when(permissionRepository.save(Mockito.any(PermissionTicket.class))).then(AdditionalAnswers.returnsFirstArg());
|
||||
|
||||
when(scopeService.scopesMatch(anySetOf(String.class), anySetOf(String.class))).then(new Answer<Boolean>() {
|
||||
|
||||
@Override
|
||||
public Boolean answer(InvocationOnMock invocation) throws Throwable {
|
||||
Object[] arguments = invocation.getArguments();
|
||||
@SuppressWarnings("unchecked")
|
||||
Set<String> expected = (Set<String>) arguments[0];
|
||||
@SuppressWarnings("unchecked")
|
||||
Set<String> actual = (Set<String>) arguments[1];
|
||||
|
||||
return expected.containsAll(actual);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test method for {@link org.mitre.uma.service.impl.DefaultPermissionService#createTicket(org.mitre.uma.model.ResourceSet, java.util.Set)}.
|
||||
*/
|
||||
@Test
|
||||
public void testCreate_ticket() {
|
||||
|
||||
PermissionTicket perm = permissionService.createTicket(rs1, scopes1);
|
||||
|
||||
// we want there to be a non-null ticket
|
||||
assertNotNull(perm.getTicket());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreate_uuid() {
|
||||
PermissionTicket perm = permissionService.createTicket(rs1, scopes1);
|
||||
|
||||
// we expect this to be a UUID
|
||||
UUID uuid = UUID.fromString(perm.getTicket());
|
||||
|
||||
assertNotNull(uuid);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreate_differentTicketsSameClient() {
|
||||
|
||||
PermissionTicket perm1 = permissionService.createTicket(rs1, scopes1);
|
||||
PermissionTicket perm2 = permissionService.createTicket(rs1, scopes1);
|
||||
|
||||
assertNotNull(perm1.getTicket());
|
||||
assertNotNull(perm2.getTicket());
|
||||
|
||||
// make sure these are different from each other
|
||||
assertThat(perm1.getTicket(), not(equalTo(perm2.getTicket())));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreate_differentTicketsDifferentClient() {
|
||||
|
||||
PermissionTicket perm1 = permissionService.createTicket(rs1, scopes1);
|
||||
PermissionTicket perm2 = permissionService.createTicket(rs2, scopes2);
|
||||
|
||||
assertNotNull(perm1.getTicket());
|
||||
assertNotNull(perm2.getTicket());
|
||||
|
||||
// make sure these are different from each other
|
||||
assertThat(perm1.getTicket(), not(equalTo(perm2.getTicket())));
|
||||
|
||||
}
|
||||
|
||||
@Test(expected = InsufficientScopeException.class)
|
||||
public void testCreate_scopeMismatch() {
|
||||
@SuppressWarnings("unused")
|
||||
// try to get scopes outside of what we're allowed to do, this should throw an exception
|
||||
PermissionTicket perm = permissionService.createTicket(rs1, scopes2);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2015 The MITRE Corporation
|
||||
* and the MIT Kerberos and 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.service.impl;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mitre.uma.model.ResourceSet;
|
||||
import org.mitre.uma.repository.ResourceSetRepository;
|
||||
import org.mockito.AdditionalAnswers;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class TestDefaultResourceSetService {
|
||||
|
||||
@Mock
|
||||
private ResourceSetRepository repository;
|
||||
|
||||
@InjectMocks
|
||||
private DefaultResourceSetService resourceSetService;
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
when(repository.save(any(ResourceSet.class))).then(AdditionalAnswers.returnsFirstArg());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link org.mitre.uma.service.impl.DefaultResourceSetService#saveNew(org.mitre.uma.model.ResourceSet)}.
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testSaveNew_hasId() {
|
||||
|
||||
ResourceSet rs = new ResourceSet();
|
||||
rs.setId(1L);
|
||||
|
||||
resourceSetService.saveNew(rs);
|
||||
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testUpdate_nullId() {
|
||||
ResourceSet rs = new ResourceSet();
|
||||
rs.setId(1L);
|
||||
|
||||
ResourceSet rs2 = new ResourceSet();
|
||||
|
||||
resourceSetService.update(rs, rs2);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testUpdate_nullId2() {
|
||||
ResourceSet rs = new ResourceSet();
|
||||
|
||||
ResourceSet rs2 = new ResourceSet();
|
||||
rs2.setId(1L);
|
||||
|
||||
resourceSetService.update(rs, rs2);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testUpdate_mismatchedIds() {
|
||||
ResourceSet rs = new ResourceSet();
|
||||
rs.setId(1L);
|
||||
|
||||
ResourceSet rs2 = new ResourceSet();
|
||||
rs2.setId(2L);
|
||||
|
||||
resourceSetService.update(rs, rs2);
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue