From f0c949fd094a858e1665e9a0cdc8b6ce51767a87 Mon Sep 17 00:00:00 2001 From: Justin Richer Date: Thu, 5 Jul 2012 17:14:51 -0400 Subject: [PATCH] added scope-based filter for userinfo --- .../mitre/openid/connect/model/Address.java | 2 + .../openid/connect/model/DefaultUserInfo.java | 35 +---- .../openid/connect/view/JSONUserInfoView.java | 54 +++++--- .../openid/connect/view/POCOUserInfoView.java | 131 ++++++++++-------- .../openid/connect/web/UserInfoEndpoint.java | 29 ++-- 5 files changed, 133 insertions(+), 118 deletions(-) diff --git a/openid-connect-common/src/main/java/org/mitre/openid/connect/model/Address.java b/openid-connect-common/src/main/java/org/mitre/openid/connect/model/Address.java index 0d57b0193..82def3ec2 100644 --- a/openid-connect-common/src/main/java/org/mitre/openid/connect/model/Address.java +++ b/openid-connect-common/src/main/java/org/mitre/openid/connect/model/Address.java @@ -20,8 +20,10 @@ import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; +import javax.persistence.Table; @Entity +@Table(name="address") public class Address { diff --git a/openid-connect-common/src/main/java/org/mitre/openid/connect/model/DefaultUserInfo.java b/openid-connect-common/src/main/java/org/mitre/openid/connect/model/DefaultUserInfo.java index 81147bfbe..82f64b01b 100644 --- a/openid-connect-common/src/main/java/org/mitre/openid/connect/model/DefaultUserInfo.java +++ b/openid-connect-common/src/main/java/org/mitre/openid/connect/model/DefaultUserInfo.java @@ -17,6 +17,8 @@ package org.mitre.openid.connect.model; import javax.persistence.Basic; import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; @@ -54,43 +56,12 @@ public class DefaultUserInfo implements UserInfo { private String updatedTime; - public JsonObject toJson() { - JsonObject obj = new JsonObject(); - - obj.addProperty("user_id", getUserId()); - obj.addProperty("name", getName()); - obj.addProperty("given_name", getGivenName()); - obj.addProperty("family_name", getFamilyName()); - obj.addProperty("middle_name", getMiddleName()); - obj.addProperty("nickname", getNickname()); - obj.addProperty("profile", getProfile()); - obj.addProperty("picture", getPicture()); - obj.addProperty("website", getWebsite()); - obj.addProperty("verified", getVerified()); - obj.addProperty("gender", getGender()); - obj.addProperty("zone_info", getZoneinfo()); - obj.addProperty("locale", getLocale()); - obj.addProperty("phone_number", getPhoneNumber()); - obj.addProperty("updated_time", getUpdatedTime()); - - JsonObject addr = new JsonObject(); - addr.addProperty("formatted", getAddress().getFormatted()); - addr.addProperty("street_address", getAddress().getStreetAddress()); - addr.addProperty("locality", getAddress().getLocality()); - addr.addProperty("region", getAddress().getRegion()); - addr.addProperty("postal_code", getAddress().getPostalCode()); - addr.addProperty("country", getAddress().getCountry()); - - obj.add("address", addr); - - return obj; - } - /* (non-Javadoc) * @see org.mitre.openid.connect.model.UserInfo#getUserId() */ @Override @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) public String getUserId() { return userId; } diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/JSONUserInfoView.java b/openid-connect-server/src/main/java/org/mitre/openid/connect/view/JSONUserInfoView.java index dab5b03f2..9f69e3e12 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/JSONUserInfoView.java +++ b/openid-connect-server/src/main/java/org/mitre/openid/connect/view/JSONUserInfoView.java @@ -17,6 +17,7 @@ package org.mitre.openid.connect.view; import java.io.Writer; import java.util.Map; +import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -42,6 +43,8 @@ public class JSONUserInfoView extends AbstractView{ UserInfo userInfo = (UserInfo) model.get("userInfo"); + Set scope = (Set) model.get("scope"); + Gson gson = new GsonBuilder() .setExclusionStrategies(new ExclusionStrategy() { @@ -62,31 +65,42 @@ public class JSONUserInfoView extends AbstractView{ response.setContentType("application/json"); Writer out = response.getWriter(); - gson.toJson(toJson(userInfo),out); + gson.toJson(toJson(userInfo, scope), out); } - private JsonObject toJson(UserInfo ui) { + private JsonObject toJson(UserInfo ui, Set scope) { JsonObject obj = new JsonObject(); - obj.addProperty("user_id", ui.getUserId()); - obj.addProperty("name", ui.getName()); - obj.addProperty("given_name", ui.getGivenName()); - obj.addProperty("family_name", ui.getFamilyName()); - obj.addProperty("middle_name", ui.getMiddleName()); - obj.addProperty("nickname", ui.getNickname()); - obj.addProperty("email", ui.getEmail()); - obj.addProperty("profile", ui.getProfile()); - obj.addProperty("picture", ui.getPicture()); - obj.addProperty("email", ui.getEmail()); - obj.addProperty("website", ui.getWebsite()); - obj.addProperty("verified", ui.getVerified()); - obj.addProperty("gender", ui.getGender()); - obj.addProperty("zone_info", ui.getZoneinfo()); - obj.addProperty("locale", ui.getLocale()); - obj.addProperty("phone_number", ui.getPhoneNumber()); - obj.addProperty("updated_time", ui.getUpdatedTime()); + if (scope.contains("openid")) { + obj.addProperty("user_id", ui.getUserId()); + } - if (ui.getAddress() != null) { + if (scope.contains("profile")) { + obj.addProperty("name", ui.getName()); + obj.addProperty("given_name", ui.getGivenName()); + obj.addProperty("family_name", ui.getFamilyName()); + obj.addProperty("middle_name", ui.getMiddleName()); + obj.addProperty("nickname", ui.getNickname()); + obj.addProperty("profile", ui.getProfile()); + obj.addProperty("picture", ui.getPicture()); + obj.addProperty("website", ui.getWebsite()); + obj.addProperty("gender", ui.getGender()); + obj.addProperty("zone_info", ui.getZoneinfo()); + obj.addProperty("locale", ui.getLocale()); + obj.addProperty("updated_time", ui.getUpdatedTime()); + // TODO: preferred_username + } + + if (scope.contains("email")) { + obj.addProperty("email", ui.getEmail()); + obj.addProperty("verified", ui.getVerified()); + } + + if (scope.contains("phone")) { + obj.addProperty("phone_number", ui.getPhoneNumber()); + } + + if (scope.contains("address") && ui.getAddress() != null) { JsonObject addr = new JsonObject(); addr.addProperty("formatted", ui.getAddress().getFormatted()); diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/POCOUserInfoView.java b/openid-connect-server/src/main/java/org/mitre/openid/connect/view/POCOUserInfoView.java index 26a2fb44b..fbf6ac8bb 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/POCOUserInfoView.java +++ b/openid-connect-server/src/main/java/org/mitre/openid/connect/view/POCOUserInfoView.java @@ -17,6 +17,7 @@ package org.mitre.openid.connect.view; import java.io.Writer; import java.util.Map; +import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -43,6 +44,8 @@ public class POCOUserInfoView extends AbstractView{ UserInfo userInfo = (UserInfo) model.get("userInfo"); + Set scope = (Set) model.get("scope"); + Gson gson = new GsonBuilder() .setExclusionStrategies(new ExclusionStrategy() { @@ -63,10 +66,10 @@ public class POCOUserInfoView extends AbstractView{ response.setContentType("application/json"); Writer out = response.getWriter(); - gson.toJson(toPoco(userInfo),out); + gson.toJson(toPoco(userInfo, scope), out); } - private JsonObject toPoco(UserInfo ui) { + private JsonObject toPoco(UserInfo ui, Set scope) { JsonObject poco = new JsonObject(); // Envelope Info @@ -76,74 +79,88 @@ public class POCOUserInfoView extends AbstractView{ // Build the entry for this userInfo, then add it to entries, then add it to poco JsonObject entry = new JsonObject(); - entry.addProperty("id", ui.getUserId()); - entry.addProperty("displayName", ui.getNickname()); - if(ui.getFamilyName() != null - || ui.getGivenName() != null - || ui.getMiddleName() != null - || ui.getName() != null) { - JsonObject name = new JsonObject(); - name.addProperty("familyName", ui.getFamilyName()); - name.addProperty("givenName", ui.getGivenName()); - name.addProperty("middleName", ui.getMiddleName()); - name.addProperty("formatted", ui.getName()); - entry.add("name", name); + if (scope.contains("openid")) { + entry.addProperty("id", ui.getUserId()); } - entry.addProperty("gender", ui.getGender()); - - if(ui.getEmail() != null) { - JsonObject email = new JsonObject(); - email.addProperty("value", ui.getEmail()); + if (scope.contains("profile")) { + entry.addProperty("displayName", ui.getNickname()); - JsonArray emailArray = new JsonArray(); - emailArray.add(email); - entry.add("emails", emailArray); - } + if(ui.getFamilyName() != null + || ui.getGivenName() != null + || ui.getMiddleName() != null + || ui.getName() != null) { + JsonObject name = new JsonObject(); + name.addProperty("familyName", ui.getFamilyName()); + name.addProperty("givenName", ui.getGivenName()); + name.addProperty("middleName", ui.getMiddleName()); + name.addProperty("formatted", ui.getName()); + entry.add("name", name); + } - if(ui.getPhoneNumber() != null){ - JsonObject phone = new JsonObject(); - phone.addProperty("value", ui.getPhoneNumber()); + entry.addProperty("gender", ui.getGender()); + // TODO: preferred_username + if(ui.getPicture() != null){ + JsonObject photo = new JsonObject(); + photo.addProperty("value", ui.getPicture()); + + JsonArray photoArray = new JsonArray(); + photoArray.add(photo); + entry.add("photos", photoArray); + } - JsonArray phoneArray = new JsonArray(); - phoneArray.add(phone); - entry.add("phoneNumbers", phoneArray); - } - - if(ui.getPicture() != null){ - JsonObject photo = new JsonObject(); - photo.addProperty("value", ui.getPicture()); + if(ui.getWebsite() != null) { + JsonObject website = new JsonObject(); + website.addProperty("value", ui.getWebsite()); + + JsonArray websiteArray = new JsonArray(); + websiteArray.add(website); + entry.add("urls", websiteArray); + } + + entry.addProperty("updated", ui.getUpdatedTime()); - JsonArray photoArray = new JsonArray(); - photoArray.add(photo); - entry.add("photos", photoArray); } - if(ui.getWebsite() != null) { - JsonObject website = new JsonObject(); - website.addProperty("value", ui.getWebsite()); - - JsonArray websiteArray = new JsonArray(); - websiteArray.add(website); - entry.add("urls", websiteArray); + if (scope.contains("email")) { + if(ui.getEmail() != null) { + JsonObject email = new JsonObject(); + email.addProperty("value", ui.getEmail()); + + JsonArray emailArray = new JsonArray(); + emailArray.add(email); + entry.add("emails", emailArray); + } } - if(ui.getAddress() != null) { - JsonObject addr = new JsonObject(); - addr.addProperty("formatted", ui.getAddress().getFormatted()); - addr.addProperty("streetAddress", ui.getAddress().getStreetAddress()); - addr.addProperty("locality", ui.getAddress().getLocality()); - addr.addProperty("region", ui.getAddress().getRegion()); - addr.addProperty("postalCode", ui.getAddress().getPostalCode()); - addr.addProperty("country", ui.getAddress().getCountry()); - - JsonArray addrArray = new JsonArray(); - addrArray.add(addr); - entry.add("addresses", addrArray); + if (scope.contains("phone")) { + if(ui.getPhoneNumber() != null){ + JsonObject phone = new JsonObject(); + phone.addProperty("value", ui.getPhoneNumber()); + + JsonArray phoneArray = new JsonArray(); + phoneArray.add(phone); + entry.add("phoneNumbers", phoneArray); + } + } - entry.addProperty("updated", ui.getUpdatedTime()); + if (scope.contains("address")) { + if(ui.getAddress() != null) { + JsonObject addr = new JsonObject(); + addr.addProperty("formatted", ui.getAddress().getFormatted()); + addr.addProperty("streetAddress", ui.getAddress().getStreetAddress()); + addr.addProperty("locality", ui.getAddress().getLocality()); + addr.addProperty("region", ui.getAddress().getRegion()); + addr.addProperty("postalCode", ui.getAddress().getPostalCode()); + addr.addProperty("country", ui.getAddress().getCountry()); + + JsonArray addrArray = new JsonArray(); + addrArray.add(addr); + entry.add("addresses", addrArray); + } + } JsonArray entryArray = new JsonArray(); entryArray.add(entry); diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/UserInfoEndpoint.java b/openid-connect-server/src/main/java/org/mitre/openid/connect/web/UserInfoEndpoint.java index cc822cbbd..8b3646963 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/UserInfoEndpoint.java +++ b/openid-connect-server/src/main/java/org/mitre/openid/connect/web/UserInfoEndpoint.java @@ -16,16 +16,21 @@ package org.mitre.openid.connect.web; import java.security.Principal; +import java.util.Set; import org.mitre.oauth2.model.ClientDetailsEntity; import org.mitre.oauth2.model.OAuth2AccessTokenEntity; import org.mitre.oauth2.service.OAuth2TokenEntityService; import org.mitre.openid.connect.exception.UnknownUserInfoSchemaException; +import org.mitre.openid.connect.model.DefaultUserInfo; import org.mitre.openid.connect.model.UserInfo; import org.mitre.openid.connect.service.UserInfoService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.oauth2.provider.OAuth2Authentication; 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; @@ -55,21 +60,17 @@ public class UserInfoEndpoint { /** * Get information about the user as specified in the accessToken->idToken included in this request * - * @param accessToken the Access Token associated with this request - * @param schema the data schema to use, default is openid - * @param mav the ModelAndView object associated with this request - * @return JSON or JWT response containing UserInfo data * @throws UsernameNotFoundException if the user does not exist or cannot be found * @throws UnknownUserInfoSchemaException if an unknown schema is used */ + @PreAuthorize("hasRole('ROLE_USER')") // TODO: need to add the check for the "openid" scope, which is REQUIRED @RequestMapping(value="/userinfo", method= {RequestMethod.GET, RequestMethod.POST}) - public ModelAndView getInfo(Principal p, @RequestParam("schema") String schema, ModelAndView mav) { + public String getInfo(Principal p, @RequestParam("schema") String schema, Model model) { - if (p == null) { throw new UsernameNotFoundException("Invalid User"); } - + String viewName = null; if (schema.equalsIgnoreCase( openIdSchema )){ viewName = jsonUserInfoViewName; @@ -85,8 +86,18 @@ public class UserInfoEndpoint { throw new UsernameNotFoundException("Invalid User"); } - return new ModelAndView(viewName, "userInfo", userInfo); + if (p instanceof OAuth2Authentication) { + OAuth2Authentication authentication = (OAuth2Authentication)p; + + model.addAttribute("scope", authentication.getAuthorizationRequest().getScope()); + } + + model.addAttribute("userInfo", userInfo); + + //return new ModelAndView(viewName, "userInfo", userInfo); + + return viewName; } - + }