Marked classes where error handling needs to be added/changed
parent
0f6faf3609
commit
1630814b9f
|
@ -11,16 +11,13 @@ import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||||
import org.mitre.oauth2.service.ClientDetailsEntityService;
|
import org.mitre.oauth2.service.ClientDetailsEntityService;
|
||||||
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
|
|
||||||
import org.springframework.security.oauth2.common.exceptions.InvalidScopeException;
|
import org.springframework.security.oauth2.common.exceptions.InvalidScopeException;
|
||||||
import org.springframework.security.oauth2.common.util.OAuth2Utils;
|
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
|
||||||
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
||||||
import org.springframework.security.oauth2.provider.ClientDetailsService;
|
|
||||||
import org.springframework.security.oauth2.provider.DefaultAuthorizationRequest;
|
import org.springframework.security.oauth2.provider.DefaultAuthorizationRequest;
|
||||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||||
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
|
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
|
||||||
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
@ -56,7 +53,7 @@ public class ChainedTokenGranter extends AbstractTokenGranter {
|
||||||
* @see org.springframework.security.oauth2.provider.token.AbstractTokenGranter#getOAuth2Authentication(org.springframework.security.oauth2.provider.AuthorizationRequest)
|
* @see org.springframework.security.oauth2.provider.token.AbstractTokenGranter#getOAuth2Authentication(org.springframework.security.oauth2.provider.AuthorizationRequest)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected OAuth2Authentication getOAuth2Authentication(AuthorizationRequest authorizationRequest) {
|
protected OAuth2Authentication getOAuth2Authentication(AuthorizationRequest authorizationRequest) throws AuthenticationException, InvalidTokenException {
|
||||||
// read and load up the existing token
|
// read and load up the existing token
|
||||||
String incomingTokenValue = authorizationRequest.getAuthorizationParameters().get("token");
|
String incomingTokenValue = authorizationRequest.getAuthorizationParameters().get("token");
|
||||||
OAuth2AccessTokenEntity incomingToken = tokenServices.readAccessToken(incomingTokenValue);
|
OAuth2AccessTokenEntity incomingToken = tokenServices.readAccessToken(incomingTokenValue);
|
||||||
|
|
|
@ -14,8 +14,10 @@ import org.mitre.oauth2.service.ClientDetailsEntityService;
|
||||||
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
||||||
import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
|
import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||||
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
|
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
|
||||||
|
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
|
||||||
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
||||||
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
|
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
@ -56,7 +58,7 @@ public class JwtAssertionTokenGranter extends AbstractTokenGranter {
|
||||||
* @see org.springframework.security.oauth2.provider.token.AbstractTokenGranter#getOAuth2Authentication(org.springframework.security.oauth2.provider.AuthorizationRequest)
|
* @see org.springframework.security.oauth2.provider.token.AbstractTokenGranter#getOAuth2Authentication(org.springframework.security.oauth2.provider.AuthorizationRequest)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected OAuth2AccessToken getAccessToken(AuthorizationRequest authorizationRequest) {
|
protected OAuth2AccessToken getAccessToken(AuthorizationRequest authorizationRequest) throws AuthenticationException, InvalidTokenException {
|
||||||
// read and load up the existing token
|
// read and load up the existing token
|
||||||
String incomingTokenValue = authorizationRequest.getAuthorizationParameters().get("assertion");
|
String incomingTokenValue = authorizationRequest.getAuthorizationParameters().get("assertion");
|
||||||
OAuth2AccessTokenEntity incomingToken = tokenServices.readAccessToken(incomingTokenValue);
|
OAuth2AccessTokenEntity incomingToken = tokenServices.readAccessToken(incomingTokenValue);
|
||||||
|
|
|
@ -25,21 +25,18 @@ import org.mitre.oauth2.service.ClientDetailsEntityService;
|
||||||
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
|
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
|
||||||
import org.springframework.security.oauth2.common.exceptions.InvalidScopeException;
|
import org.springframework.security.oauth2.common.exceptions.InvalidScopeException;
|
||||||
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
|
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
|
||||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
|
||||||
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
|
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
import com.google.common.base.Objects;
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class IntrospectionEndpoint {
|
public class IntrospectionEndpoint {
|
||||||
|
@ -93,10 +90,19 @@ public class IntrospectionEndpoint {
|
||||||
|
|
||||||
if (Strings.isNullOrEmpty(tokenValue)) {
|
if (Strings.isNullOrEmpty(tokenValue)) {
|
||||||
throw new InvalidTokenException("No token found!");
|
throw new InvalidTokenException("No token found!");
|
||||||
|
//TODO: Error Handling
|
||||||
}
|
}
|
||||||
|
|
||||||
OAuth2AccessTokenEntity token = tokenServices.readAccessToken(tokenValue);
|
OAuth2AccessTokenEntity token = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
token = tokenServices.readAccessToken(tokenValue);
|
||||||
|
} catch (InvalidTokenException e) {
|
||||||
|
//TODO: Error Handling
|
||||||
|
} catch (AuthenticationException e) {
|
||||||
|
//TODO: Error Handling
|
||||||
|
}
|
||||||
|
|
||||||
ClientDetailsEntity tokenClient = token.getClient();
|
ClientDetailsEntity tokenClient = token.getClient();
|
||||||
// clientID is the principal name in the authentication
|
// clientID is the principal name in the authentication
|
||||||
String clientId = p.getName();
|
String clientId = p.getName();
|
||||||
|
@ -114,12 +120,15 @@ public class IntrospectionEndpoint {
|
||||||
return modelAndView;
|
return modelAndView;
|
||||||
} else {
|
} else {
|
||||||
throw new InvalidScopeException("Tried to introspect a token of different scope");
|
throw new InvalidScopeException("Tried to introspect a token of different scope");
|
||||||
|
//TODO: Error Handling
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new InvalidClientException("Client is not allowed to call introspection endpoint.");
|
throw new InvalidClientException("Client is not allowed to call introspection endpoint.");
|
||||||
|
//TODO: Error Handling
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new InvalidClientException("Client not found.");
|
throw new InvalidClientException("Client not found.");
|
||||||
|
//TODO: Error Handling
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
*/
|
*/
|
||||||
package org.mitre.oauth2.web;
|
package org.mitre.oauth2.web;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -29,6 +28,8 @@ import org.mitre.oauth2.service.ClientDetailsEntityService;
|
||||||
import org.mitre.oauth2.service.SystemScopeService;
|
import org.mitre.oauth2.service.SystemScopeService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
|
||||||
|
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
|
||||||
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
||||||
import org.springframework.security.oauth2.provider.ClientDetails;
|
import org.springframework.security.oauth2.provider.ClientDetails;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
@ -67,11 +68,13 @@ public class OAuthConfirmationController {
|
||||||
|
|
||||||
//AuthorizationRequest clientAuth = (AuthorizationRequest) model.remove("authorizationRequest");
|
//AuthorizationRequest clientAuth = (AuthorizationRequest) model.remove("authorizationRequest");
|
||||||
|
|
||||||
|
//TODO: Error Handling
|
||||||
|
//Throws OAuth2Exception, InvalidClientException, IllegalArgumentException
|
||||||
ClientDetails client = clientService.loadClientByClientId(clientAuth.getClientId());
|
ClientDetails client = clientService.loadClientByClientId(clientAuth.getClientId());
|
||||||
|
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
throw new ClientNotFoundException("Client not found: " + clientAuth.getClientId());
|
throw new ClientNotFoundException("Client not found: " + clientAuth.getClientId());
|
||||||
|
//TODO: Error Handling
|
||||||
}
|
}
|
||||||
|
|
||||||
model.put("auth_request", clientAuth);
|
model.put("auth_request", clientAuth);
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.mitre.oauth2.model.OAuth2RefreshTokenEntity;
|
||||||
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
|
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
|
||||||
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
||||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||||
|
@ -57,15 +58,20 @@ public class RevocationEndpoint {
|
||||||
refreshToken = tokenServices.getRefreshToken(tokenValue);
|
refreshToken = tokenServices.getRefreshToken(tokenValue);
|
||||||
} catch (InvalidTokenException e) {
|
} catch (InvalidTokenException e) {
|
||||||
// it's OK if either of these tokens are bad
|
// it's OK if either of these tokens are bad
|
||||||
|
//TODO: Error Handling
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
accessToken = tokenServices.readAccessToken(tokenValue);
|
accessToken = tokenServices.readAccessToken(tokenValue);
|
||||||
} catch (InvalidTokenException e) {
|
} catch (InvalidTokenException e) {
|
||||||
// it's OK if either of these tokens are bad
|
// it's OK if either of these tokens are bad
|
||||||
|
//TODO: Error Handling
|
||||||
|
} catch (AuthenticationException e) {
|
||||||
|
//TODO: Error Handling
|
||||||
}
|
}
|
||||||
|
|
||||||
if (refreshToken == null && accessToken == null) {
|
if (refreshToken == null && accessToken == null) {
|
||||||
|
//TODO: Error Handling
|
||||||
// TODO: this should throw a 400 with a JSON error code
|
// TODO: this should throw a 400 with a JSON error code
|
||||||
throw new InvalidTokenException("Invalid OAuth token: " + tokenValue);
|
throw new InvalidTokenException("Invalid OAuth token: " + tokenValue);
|
||||||
}
|
}
|
||||||
|
@ -82,12 +88,14 @@ public class RevocationEndpoint {
|
||||||
if (!refreshToken.getClient().getClientId().equals(clientAuth.getClientId())) {
|
if (!refreshToken.getClient().getClientId().equals(clientAuth.getClientId())) {
|
||||||
// trying to revoke a token we don't own, fail
|
// trying to revoke a token we don't own, fail
|
||||||
// TODO: this should throw a 403
|
// TODO: this should throw a 403
|
||||||
|
//TODO: Error Handling
|
||||||
throw new PermissionDeniedException("Client tried to revoke a token it doesn't own");
|
throw new PermissionDeniedException("Client tried to revoke a token it doesn't own");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!accessToken.getClient().getClientId().equals(clientAuth.getClientId())) {
|
if (!accessToken.getClient().getClientId().equals(clientAuth.getClientId())) {
|
||||||
// trying to revoke a token we don't own, fail
|
// trying to revoke a token we don't own, fail
|
||||||
// TODO: this should throw a 403
|
// TODO: this should throw a 403
|
||||||
|
//TODO: Error Handling
|
||||||
throw new PermissionDeniedException("Client tried to revoke a token it doesn't own");
|
throw new PermissionDeniedException("Client tried to revoke a token it doesn't own");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,7 @@ public class JsonEntityView extends AbstractView {
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
||||||
|
//TODO: Error Handling
|
||||||
logger.error("IOException in JsonEntityView.java: ", e);
|
logger.error("IOException in JsonEntityView.java: ", e);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author jricher
|
* @author jricher
|
||||||
|
@ -63,13 +64,23 @@ public class BlacklistAPI {
|
||||||
@RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
|
@RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
|
||||||
public String addNewBlacklistedSite(@RequestBody String jsonString, ModelMap m, Principal p) {
|
public String addNewBlacklistedSite(@RequestBody String jsonString, ModelMap m, Principal p) {
|
||||||
|
|
||||||
JsonObject json = parser.parse(jsonString).getAsJsonObject();
|
JsonObject json;
|
||||||
|
|
||||||
BlacklistedSite blacklist = gson.fromJson(json, BlacklistedSite.class);
|
BlacklistedSite blacklist = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
json = parser.parse(jsonString).getAsJsonObject();
|
||||||
|
blacklist = gson.fromJson(json, BlacklistedSite.class);
|
||||||
|
BlacklistedSite newBlacklist = blacklistService.saveNew(blacklist);
|
||||||
|
m.put("entity", newBlacklist);
|
||||||
|
|
||||||
|
} catch (JsonSyntaxException e) {
|
||||||
|
//TODO: Error Handling
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
BlacklistedSite newBlacklist = blacklistService.saveNew(blacklist);
|
|
||||||
|
|
||||||
m.put("entity", newBlacklist);
|
|
||||||
|
|
||||||
return "jsonEntityView";
|
return "jsonEntityView";
|
||||||
|
|
||||||
|
@ -81,9 +92,21 @@ public class BlacklistAPI {
|
||||||
@RequestMapping(value="/{id}", method = RequestMethod.PUT, consumes = "application/json", produces = "application/json")
|
@RequestMapping(value="/{id}", method = RequestMethod.PUT, consumes = "application/json", produces = "application/json")
|
||||||
public String updateBlacklistedSite(@PathVariable("id") Long id, @RequestBody String jsonString, ModelMap m, Principal p) {
|
public String updateBlacklistedSite(@PathVariable("id") Long id, @RequestBody String jsonString, ModelMap m, Principal p) {
|
||||||
|
|
||||||
JsonObject json = parser.parse(jsonString).getAsJsonObject();
|
JsonObject json;
|
||||||
|
|
||||||
|
BlacklistedSite blacklist = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
json = parser.parse(jsonString).getAsJsonObject();
|
||||||
|
blacklist = gson.fromJson(json, BlacklistedSite.class);
|
||||||
|
|
||||||
|
} catch (JsonSyntaxException e) {
|
||||||
|
//TODO: Error Handling
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
BlacklistedSite blacklist = gson.fromJson(json, BlacklistedSite.class);
|
|
||||||
|
|
||||||
BlacklistedSite oldBlacklist = blacklistService.getById(id);
|
BlacklistedSite oldBlacklist = blacklistService.getById(id);
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Michael Jett <mjett@mitre.org>
|
* @author Michael Jett <mjett@mitre.org>
|
||||||
|
@ -124,10 +125,18 @@ public class ClientAPI {
|
||||||
@RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
|
@RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
|
||||||
public String apiAddClient(@RequestBody String jsonString, Model m, Authentication auth) {
|
public String apiAddClient(@RequestBody String jsonString, Model m, Authentication auth) {
|
||||||
|
|
||||||
JsonObject json = parser.parse(jsonString).getAsJsonObject();
|
JsonObject json = null;
|
||||||
|
ClientDetailsEntity client = null;
|
||||||
ClientDetailsEntity client = gson.fromJson(json, ClientDetailsEntity.class);
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
json = parser.parse(jsonString).getAsJsonObject();
|
||||||
|
client = gson.fromJson(json, ClientDetailsEntity.class);
|
||||||
|
} catch (JsonSyntaxException e) {
|
||||||
|
//TODO: Error Handling
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// if they leave the client secret empty, force it to be generated
|
// if they leave the client secret empty, force it to be generated
|
||||||
if (Strings.isNullOrEmpty(client.getClientId())) {
|
if (Strings.isNullOrEmpty(client.getClientId())) {
|
||||||
client = clientService.generateClientId(client);
|
client = clientService.generateClientId(client);
|
||||||
|
@ -165,14 +174,24 @@ public class ClientAPI {
|
||||||
@RequestMapping(value="/{id}", method = RequestMethod.PUT, consumes = "application/json", produces = "application/json")
|
@RequestMapping(value="/{id}", method = RequestMethod.PUT, consumes = "application/json", produces = "application/json")
|
||||||
public String apiUpdateClient(@PathVariable("id") Long id, @RequestBody String jsonString, Model m, Authentication auth) {
|
public String apiUpdateClient(@PathVariable("id") Long id, @RequestBody String jsonString, Model m, Authentication auth) {
|
||||||
|
|
||||||
// TODO: sanity check if the thing really is a JSON object
|
JsonObject json = null;
|
||||||
JsonObject json = parser.parse(jsonString).getAsJsonObject();
|
ClientDetailsEntity client = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// parse the client passed in (from JSON) and fetch the old client from the store
|
||||||
|
json = parser.parse(jsonString).getAsJsonObject();
|
||||||
|
client = gson.fromJson(json, ClientDetailsEntity.class);
|
||||||
|
} catch (JsonSyntaxException e) {
|
||||||
|
//TODO: Error Handling
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// parse the client passed in (from JSON) and fetch the old client from the store
|
|
||||||
ClientDetailsEntity client = gson.fromJson(json, ClientDetailsEntity.class);
|
|
||||||
ClientDetailsEntity oldClient = clientService.getClientById(id);
|
ClientDetailsEntity oldClient = clientService.getClientById(id);
|
||||||
|
|
||||||
if (oldClient == null) {
|
if (oldClient == null) {
|
||||||
|
//TODO: Error Handling
|
||||||
|
//Is this exception caught by a view?
|
||||||
throw new ClientNotFoundException();
|
throw new ClientNotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,6 +252,8 @@ public class ClientAPI {
|
||||||
public String apiShowClient(@PathVariable("id") Long id, Model model, Authentication auth) {
|
public String apiShowClient(@PathVariable("id") Long id, Model model, Authentication auth) {
|
||||||
ClientDetailsEntity client = clientService.getClientById(id);
|
ClientDetailsEntity client = clientService.getClientById(id);
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
|
//TODO: Error Handling
|
||||||
|
//Is this error handled by a view?
|
||||||
throw new ClientNotFoundException("Could not find client: " + id);
|
throw new ClientNotFoundException("Could not find client: " + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,12 @@
|
||||||
|
|
||||||
package org.mitre.openid.connect.web;
|
package org.mitre.openid.connect.web;
|
||||||
|
|
||||||
import java.security.Principal;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.mitre.jose.JWEAlgorithmEmbed;
|
import org.mitre.jose.JWSAlgorithmEntity;
|
||||||
import org.mitre.jose.JWEEncryptionMethodEmbed;
|
import org.mitre.oauth2.exception.ClientNotFoundException;
|
||||||
import org.mitre.jose.JWSAlgorithmEmbed;
|
|
||||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||||
import org.mitre.oauth2.model.ClientDetailsEntity.AppType;
|
import org.mitre.oauth2.model.ClientDetailsEntity.AppType;
|
||||||
import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod;
|
import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod;
|
||||||
|
@ -19,32 +18,26 @@ import org.mitre.oauth2.service.ClientDetailsEntityService;
|
||||||
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
||||||
import org.mitre.oauth2.service.SystemScopeService;
|
import org.mitre.oauth2.service.SystemScopeService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
|
||||||
|
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
|
||||||
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
|
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
|
||||||
import org.springframework.security.oauth2.provider.DefaultAuthorizationRequest;
|
import org.springframework.security.oauth2.provider.DefaultAuthorizationRequest;
|
||||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||||
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
|
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.ModelMap;
|
||||||
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.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.google.gson.Gson;
|
import com.nimbusds.jose.JWSAlgorithm;
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
import com.google.gson.JsonSyntaxException;
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping(value = "register")
|
@RequestMapping(value = "register"/*, method = RequestMethod.POST*/)
|
||||||
public class ClientDynamicRegistrationEndpoint {
|
public class ClientDynamicRegistrationEndpoint {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@ -56,403 +49,127 @@ public class ClientDynamicRegistrationEndpoint {
|
||||||
@Autowired
|
@Autowired
|
||||||
private SystemScopeService scopeService;
|
private SystemScopeService scopeService;
|
||||||
|
|
||||||
private JsonParser parser = new JsonParser();
|
|
||||||
private Gson gson = new Gson();
|
|
||||||
|
|
||||||
/**
|
@RequestMapping(params = "operation=client_register", produces = "application/json")
|
||||||
* Create a new Client, issue a client ID, and create a registration access token.
|
public String clientRegister(
|
||||||
* @param jsonString
|
@RequestParam(value = "redirect_uris", required = true) Set<String> redirectUris,
|
||||||
* @param m
|
@RequestParam(value = "client_name", required = false) String clientName,
|
||||||
* @param p
|
@RequestParam(value = "client_url", required = false) String clientUrl,
|
||||||
* @return
|
@RequestParam(value = "logo_url", required = false) String logoUrl,
|
||||||
*/
|
@RequestParam(value = "contacts", required = false) Set<String> contacts,
|
||||||
@RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
|
@RequestParam(value = "tos_url", required = false) String tosUrl,
|
||||||
public String registerNewClient(@RequestBody String jsonString, Model m) {
|
@RequestParam(value = "token_endpoint_auth_method", required = false) AuthMethod tokenEndpointAuthMethod,
|
||||||
|
@RequestParam(value = "policy_url", required = false) String policyUrl,
|
||||||
|
|
||||||
|
@RequestParam(value = "scope", required = false) Set<String> scope,
|
||||||
|
@RequestParam(value = "grant_type", required = false) Set<String> grantType,
|
||||||
|
|
||||||
|
@RequestParam(value = "jwk_url", required = false) String jwkUrl,
|
||||||
|
@RequestParam(value = "jwk_encryption_url", required = false) String jwkEncryptionUrl,
|
||||||
|
@RequestParam(value = "x509_url", required = false) String x509Url,
|
||||||
|
@RequestParam(value = "x509_encryption_url", required = false) String x509EncryptionUrl,
|
||||||
|
@RequestParam(value = "default_max_age", required = false) Integer defaultMaxAge,
|
||||||
|
@RequestParam(value = "default_acr", required = false) String defaultAcr,
|
||||||
|
|
||||||
|
// OPENID CONNECT EXTENSIONS BELOW
|
||||||
|
@RequestParam(value = "application_type", required = false) AppType applicationType,
|
||||||
|
@RequestParam(value = "sector_identifier_url", required = false) String sectorIdentifierUrl,
|
||||||
|
@RequestParam(value = "subject_type", required = false) SubjectType subjectType,
|
||||||
|
@RequestParam(value = "require_signed_request_object", required = false) JWSAlgorithm requireSignedRequestObject,
|
||||||
|
// TODO: JWE needs to be handled properly, see @InitBinder above -- we'll ignore these right now
|
||||||
|
/*
|
||||||
|
@RequestParam(value = "userinfo_signed_response_alg", required = false) String userinfoSignedResponseAlg,
|
||||||
|
@RequestParam(value = "userinfo_encrypted_response_alg", required = false) String userinfoEncryptedResponseAlg,
|
||||||
|
@RequestParam(value = "userinfo_encrypted_response_enc", required = false) String userinfoEncryptedResponseEnc,
|
||||||
|
@RequestParam(value = "userinfo_encrypted_response_int", required = false) String userinfoEncryptedResponseInt,
|
||||||
|
@RequestParam(value = "idtoken_signed_response_alg", required = false) String idtokenSignedResponseAlg,
|
||||||
|
@RequestParam(value = "idtoken_encrypted_response_alg", required = false) String idtokenEncryptedResponseAlg,
|
||||||
|
@RequestParam(value = "idtoken_encrypted_response_enc", required = false) String idtokenEncryptedResponseEnc,
|
||||||
|
@RequestParam(value = "idtoken_encrypted_response_int", required = false) String idtokenEncryptedResponseInt,
|
||||||
|
*/
|
||||||
|
|
||||||
|
@RequestParam(value = "require_auth_time", required = false, defaultValue = "true") Boolean requireAuthTime,
|
||||||
|
ModelMap model
|
||||||
|
) {
|
||||||
|
|
||||||
ClientDetailsEntity newClient = parse(jsonString);
|
|
||||||
|
|
||||||
if (newClient != null) {
|
// Create a new Client
|
||||||
// it parsed!
|
|
||||||
|
ClientDetailsEntity client = new ClientDetailsEntity();
|
||||||
//
|
|
||||||
// Now do some post-processing consistency checks on it
|
|
||||||
//
|
|
||||||
|
|
||||||
// clear out any spurious id/secret (clients don't get to pick)
|
|
||||||
newClient.setClientId(null);
|
|
||||||
newClient.setClientSecret(null);
|
|
||||||
|
|
||||||
// set of scopes that are OK for clients to dynamically register for
|
|
||||||
Set<SystemScope> dynScopes = scopeService.getDynReg();
|
|
||||||
|
|
||||||
// scopes that the client is asking for
|
// if it's not using a private key or no auth, then generate a secret
|
||||||
Set<SystemScope> requestedScopes = scopeService.fromStrings(newClient.getScope());
|
if (tokenEndpointAuthMethod != AuthMethod.PRIVATE_KEY && tokenEndpointAuthMethod != AuthMethod.NONE) {
|
||||||
|
client = clientService.generateClientSecret(client);
|
||||||
// if the client didn't ask for any, give them the defaults
|
|
||||||
if (requestedScopes == null || requestedScopes.isEmpty()) {
|
|
||||||
requestedScopes = scopeService.getDefaults();
|
|
||||||
}
|
|
||||||
|
|
||||||
// the scopes that the client can have must be a subset of the dynamically allowed scopes
|
|
||||||
Set<SystemScope> allowedScopes = Sets.intersection(dynScopes, requestedScopes);
|
|
||||||
|
|
||||||
newClient.setScope(scopeService.toStrings(allowedScopes));
|
|
||||||
|
|
||||||
|
|
||||||
// set default grant types if needed
|
|
||||||
if (newClient.getGrantTypes() == null || newClient.getGrantTypes().isEmpty()) {
|
|
||||||
newClient.setGrantTypes(Sets.newHashSet("authorization_code", "refresh_token")); // allow authorization code and refresh token grant types by default
|
|
||||||
}
|
|
||||||
|
|
||||||
// set default response types if needed
|
|
||||||
// TODO: these aren't checked by SECOAUTH
|
|
||||||
// TODO: the consistency between the response_type and grant_type needs to be checked by the client service, most likely
|
|
||||||
if (newClient.getResponseTypes() == null || newClient.getResponseTypes().isEmpty()) {
|
|
||||||
newClient.setResponseTypes(Sets.newHashSet("code")); // default to allowing only the auth code flow
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newClient.getTokenEndpointAuthMethod() == null) {
|
|
||||||
newClient.setTokenEndpointAuthMethod(AuthMethod.SECRET_BASIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newClient.getTokenEndpointAuthMethod() == AuthMethod.SECRET_BASIC ||
|
|
||||||
newClient.getTokenEndpointAuthMethod() == AuthMethod.SECRET_JWT ||
|
|
||||||
newClient.getTokenEndpointAuthMethod() == AuthMethod.SECRET_POST) {
|
|
||||||
|
|
||||||
// we need to generate a secret
|
|
||||||
newClient = clientService.generateClientSecret(newClient);
|
|
||||||
}
|
|
||||||
|
|
||||||
// set some defaults for token timeouts
|
|
||||||
newClient.setAccessTokenValiditySeconds((int)TimeUnit.HOURS.toSeconds(1)); // access tokens good for 1hr
|
|
||||||
newClient.setIdTokenValiditySeconds((int)TimeUnit.MINUTES.toSeconds(10)); // id tokens good for 10min
|
|
||||||
newClient.setRefreshTokenValiditySeconds(null); // refresh tokens good until revoked
|
|
||||||
|
|
||||||
// this client has been dynamically registered (obviously)
|
|
||||||
newClient.setDynamicallyRegistered(true);
|
|
||||||
|
|
||||||
// now save it
|
|
||||||
ClientDetailsEntity savedClient = clientService.saveNewClient(newClient);
|
|
||||||
|
|
||||||
// generate the registration access token
|
|
||||||
OAuth2AccessTokenEntity token = createRegistrationAccessToken(savedClient);
|
|
||||||
|
|
||||||
// send it all out to the view
|
|
||||||
m.addAttribute("client", savedClient);
|
|
||||||
m.addAttribute("code", HttpStatus.CREATED); // http 201
|
|
||||||
m.addAttribute("token", token);
|
|
||||||
|
|
||||||
return "clientInformationResponseView";
|
|
||||||
} else {
|
|
||||||
// didn't parse, this is a bad request
|
|
||||||
|
|
||||||
m.addAttribute("code", HttpStatus.BAD_REQUEST); // http 400
|
|
||||||
|
|
||||||
return "httpCodeView";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client.setContacts(contacts);
|
||||||
|
client.setApplicationType(applicationType);
|
||||||
|
client.setClientName(clientName);
|
||||||
|
client.setClientUrl(clientUrl);
|
||||||
|
client.setTosUrl(tosUrl);
|
||||||
|
client.setLogoUrl(logoUrl);
|
||||||
|
client.setRegisteredRedirectUri(redirectUris);
|
||||||
|
client.setTokenEndpointAuthMethod(tokenEndpointAuthMethod);
|
||||||
|
client.setPolicyUrl(policyUrl);
|
||||||
|
client.setJwkUrl(jwkUrl);
|
||||||
|
client.setJwkEncryptionUrl(jwkEncryptionUrl);
|
||||||
|
client.setX509Url(x509Url);
|
||||||
|
client.setX509EncryptionUrl(x509EncryptionUrl);
|
||||||
|
client.setSectorIdentifierUrl(sectorIdentifierUrl);
|
||||||
|
client.setSubjectType(subjectType);
|
||||||
|
client.setRequireSignedRequestObject(new JWSAlgorithmEntity(requireSignedRequestObject));
|
||||||
|
client.setDefaultMaxAge(defaultMaxAge);
|
||||||
|
client.setRequireAuthTime(requireAuthTime == null ? false : requireAuthTime.booleanValue());
|
||||||
|
client.setDefaultACR(defaultAcr);
|
||||||
|
|
||||||
|
// set of scopes that are OK for clients to dynamically register for
|
||||||
|
Set<SystemScope> dynScopes = scopeService.getDynReg();
|
||||||
|
|
||||||
|
// scopes that the client is asking for
|
||||||
|
Set<SystemScope> requestedScopes = scopeService.fromStrings(scope);
|
||||||
|
if (requestedScopes == null) {
|
||||||
|
requestedScopes = scopeService.getDefaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
// the scopes that the client can have must be a subset of the dynamically allowed scopes
|
||||||
|
Set<SystemScope> allowedScopes = Sets.intersection(dynScopes, requestedScopes);
|
||||||
|
|
||||||
|
client.setScope(scopeService.toStrings(allowedScopes));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (grantType != null) {
|
||||||
|
// TODO: check against some kind of grant type service for validity
|
||||||
|
client.setAuthorizedGrantTypes(grantType);
|
||||||
|
} else {
|
||||||
|
client.setAuthorizedGrantTypes(Sets.newHashSet("authorization_code", "refresh_token")); // allow authorization code and refresh token grant types
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaults for SECOAUTH functionality
|
||||||
|
// TODO: extensions to request, or configuration?
|
||||||
|
client.setAccessTokenValiditySeconds((int)TimeUnit.HOURS.toSeconds(1)); // access tokens good for 1hr
|
||||||
|
client.setIdTokenValiditySeconds((int)TimeUnit.MINUTES.toSeconds(10)); // id tokens good for 10min
|
||||||
|
client.setRefreshTokenValiditySeconds(null); // refresh tokens good until revoked
|
||||||
|
|
||||||
|
client.setDynamicallyRegistered(true);
|
||||||
|
|
||||||
|
ClientDetailsEntity saved = clientService.saveNewClient(client);
|
||||||
|
|
||||||
|
OAuth2AccessTokenEntity registrationAccessToken = createRegistrationAccessToken(client);
|
||||||
|
|
||||||
|
model.put("fullClient", Boolean.TRUE);
|
||||||
|
model.put("client", saved);
|
||||||
|
model.put("token", registrationAccessToken);
|
||||||
|
|
||||||
|
return "clientRegistration";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the meta information for a client.
|
|
||||||
* @param clientId
|
|
||||||
* @param m
|
|
||||||
* @param auth
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@PreAuthorize("hasRole('ROLE_CLIENT') and #oauth2.hasScope('" + OAuth2AccessTokenEntity.REGISTRATION_TOKEN_SCOPE + "')")
|
|
||||||
@RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = "application/json")
|
|
||||||
public String readClientConfiguration(@PathVariable("id") String clientId, Model m, OAuth2Authentication auth) {
|
|
||||||
|
|
||||||
ClientDetailsEntity client = clientService.loadClientByClientId(clientId);
|
|
||||||
|
|
||||||
if (client != null && client.getClientId().equals(auth.getAuthorizationRequest().getClientId())) {
|
|
||||||
|
|
||||||
|
|
||||||
// we return the token that we got in
|
|
||||||
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) auth.getDetails();
|
|
||||||
OAuth2AccessTokenEntity token = tokenService.readAccessToken(details.getTokenValue());
|
|
||||||
|
|
||||||
// send it all out to the view
|
|
||||||
m.addAttribute("client", client);
|
|
||||||
m.addAttribute("code", HttpStatus.OK); // http 200
|
|
||||||
m.addAttribute("token", token);
|
|
||||||
|
|
||||||
return "clientInformationResponseView";
|
|
||||||
} else {
|
|
||||||
// client mismatch
|
|
||||||
m.addAttribute("code", HttpStatus.FORBIDDEN); // http 403
|
|
||||||
|
|
||||||
return "httpCodeView";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the metainformation for a given client.
|
|
||||||
* @param clientId
|
|
||||||
* @param jsonString
|
|
||||||
* @param m
|
|
||||||
* @param auth
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@PreAuthorize("hasRole('ROLE_CLIENT') and #oauth2.hasScope('" + OAuth2AccessTokenEntity.REGISTRATION_TOKEN_SCOPE + "')")
|
|
||||||
@RequestMapping(value = "/{id}", method = RequestMethod.PUT, produces = "application/json", consumes = "application/json")
|
|
||||||
public String updateClient(@PathVariable("id") String clientId, @RequestBody String jsonString, Model m, OAuth2Authentication auth) {
|
|
||||||
|
|
||||||
|
|
||||||
ClientDetailsEntity newClient = parse(jsonString);
|
|
||||||
ClientDetailsEntity oldClient = clientService.loadClientByClientId(clientId);
|
|
||||||
|
|
||||||
if (newClient != null && oldClient != null // we have an existing client and the new one parsed
|
|
||||||
&& oldClient.getClientId().equals(auth.getAuthorizationRequest().getClientId()) // the client passed in the URI matches the one in the auth
|
|
||||||
&& oldClient.getClientId().equals(newClient.getClientId()) // the client passed in the body matches the one in the URI
|
|
||||||
) {
|
|
||||||
|
|
||||||
// a client can't ask to update its own client secret to any particular value
|
|
||||||
newClient.setClientSecret(oldClient.getClientSecret());
|
|
||||||
|
|
||||||
// we need to copy over all of the local and SECOAUTH fields
|
|
||||||
newClient.setAccessTokenValiditySeconds(oldClient.getAccessTokenValiditySeconds());
|
|
||||||
newClient.setIdTokenValiditySeconds(oldClient.getIdTokenValiditySeconds());
|
|
||||||
newClient.setRefreshTokenValiditySeconds(oldClient.getRefreshTokenValiditySeconds());
|
|
||||||
newClient.setDynamicallyRegistered(true); // it's still dynamically registered
|
|
||||||
newClient.setAllowIntrospection(oldClient.isAllowIntrospection());
|
|
||||||
newClient.setAuthorities(oldClient.getAuthorities());
|
|
||||||
newClient.setClientDescription(oldClient.getClientDescription());
|
|
||||||
newClient.setCreatedAt(oldClient.getCreatedAt());
|
|
||||||
newClient.setReuseRefreshToken(oldClient.isReuseRefreshToken());
|
|
||||||
|
|
||||||
// set of scopes that are OK for clients to dynamically register for
|
|
||||||
Set<SystemScope> dynScopes = scopeService.getDynReg();
|
|
||||||
|
|
||||||
// scopes that the client is asking for
|
|
||||||
Set<SystemScope> requestedScopes = scopeService.fromStrings(newClient.getScope());
|
|
||||||
|
|
||||||
// the scopes that the client can have must be a subset of the dynamically allowed scopes
|
|
||||||
Set<SystemScope> allowedScopes = Sets.intersection(dynScopes, requestedScopes);
|
|
||||||
|
|
||||||
// make sure that the client doesn't ask for scopes it can't have
|
|
||||||
newClient.setScope(scopeService.toStrings(allowedScopes));
|
|
||||||
|
|
||||||
// save the client
|
|
||||||
ClientDetailsEntity savedClient = clientService.updateClient(oldClient, newClient);
|
|
||||||
|
|
||||||
// we return the token that we got in
|
|
||||||
// TODO: rotate this after some set amount of time
|
|
||||||
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) auth.getDetails();
|
|
||||||
OAuth2AccessTokenEntity token = tokenService.readAccessToken(details.getTokenValue());
|
|
||||||
|
|
||||||
// send it all out to the view
|
|
||||||
m.addAttribute("client", savedClient);
|
|
||||||
m.addAttribute("code", HttpStatus.OK); // http 200
|
|
||||||
m.addAttribute("token", token);
|
|
||||||
|
|
||||||
return "clientInformationResponseView";
|
|
||||||
} else {
|
|
||||||
// client mismatch
|
|
||||||
m.addAttribute("code", HttpStatus.FORBIDDEN); // http 403
|
|
||||||
|
|
||||||
return "httpCodeView";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the indicated client from the system.
|
|
||||||
* @param clientId
|
|
||||||
* @param m
|
|
||||||
* @param auth
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@PreAuthorize("hasRole('ROLE_CLIENT') and #oauth2.hasScope('" + OAuth2AccessTokenEntity.REGISTRATION_TOKEN_SCOPE + "')")
|
|
||||||
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE, produces = "application/json")
|
|
||||||
public String deleteClient(@PathVariable("id") String clientId, Model m, OAuth2Authentication auth) {
|
|
||||||
|
|
||||||
ClientDetailsEntity client = clientService.loadClientByClientId(clientId);
|
|
||||||
|
|
||||||
if (client != null && client.getClientId().equals(auth.getAuthorizationRequest().getClientId())) {
|
|
||||||
|
|
||||||
clientService.deleteClient(client);
|
|
||||||
|
|
||||||
// we return the token that we got in
|
|
||||||
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) auth.getDetails();
|
|
||||||
OAuth2AccessTokenEntity token = tokenService.readAccessToken(details.getTokenValue());
|
|
||||||
|
|
||||||
// send it all out to the view
|
|
||||||
m.addAttribute("client", client);
|
|
||||||
m.addAttribute("code", HttpStatus.OK); // http 200
|
|
||||||
m.addAttribute("token", token);
|
|
||||||
|
|
||||||
return "clientInformationResponseView";
|
|
||||||
} else {
|
|
||||||
// client mismatch
|
|
||||||
m.addAttribute("code", HttpStatus.FORBIDDEN); // http 403
|
|
||||||
|
|
||||||
return "httpCodeView";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Create an unbound ClientDetailsEntity from the given JSON string.
|
|
||||||
*
|
|
||||||
* @param jsonString
|
|
||||||
* @return the entity if successful, null otherwise
|
|
||||||
*/
|
|
||||||
private ClientDetailsEntity parse(String jsonString) {
|
|
||||||
JsonElement jsonEl = parser.parse(jsonString);
|
|
||||||
if (jsonEl.isJsonObject()) {
|
|
||||||
|
|
||||||
JsonObject o = jsonEl.getAsJsonObject();
|
|
||||||
ClientDetailsEntity c = new ClientDetailsEntity();
|
|
||||||
|
|
||||||
// TODO: make these field names into constants
|
|
||||||
|
|
||||||
// these two fields should only be sent in the update request, and MUST match existing values
|
|
||||||
c.setClientId(getAsString(o, "client_id"));
|
|
||||||
c.setClientSecret(getAsString(o, "client_secret"));
|
|
||||||
|
|
||||||
// OAuth DynReg
|
|
||||||
c.setRedirectUris(getAsStringSet(o, "redirect_uris"));
|
|
||||||
c.setClientName(getAsString(o, "client_name"));
|
|
||||||
c.setClientUri(getAsString(o, "client_uri"));
|
|
||||||
c.setLogoUri(getAsString(o, "logo_uri"));
|
|
||||||
c.setContacts(getAsStringSet(o, "contacts"));
|
|
||||||
c.setTosUri(getAsString(o, "tos_uri"));
|
|
||||||
|
|
||||||
String authMethod = getAsString(o, "token_endpoint_auth_method");
|
|
||||||
if (authMethod != null) {
|
|
||||||
c.setTokenEndpointAuthMethod(AuthMethod.getByValue(authMethod));
|
|
||||||
}
|
|
||||||
|
|
||||||
// scope is a space-separated string
|
|
||||||
String scope = getAsString(o, "scope");
|
|
||||||
if (scope != null) {
|
|
||||||
c.setScope(Sets.newHashSet(Splitter.on(" ").split(scope)));
|
|
||||||
}
|
|
||||||
|
|
||||||
c.setGrantTypes(getAsStringSet(o, "grant_types"));
|
|
||||||
c.setPolicyUri(getAsString(o, "policy_uri"));
|
|
||||||
c.setJwksUri(getAsString(o, "jwks_uri"));
|
|
||||||
|
|
||||||
|
|
||||||
// OIDC Additions
|
|
||||||
String appType = getAsString(o, "application_type");
|
|
||||||
if (appType != null) {
|
|
||||||
c.setApplicationType(AppType.getByValue(appType));
|
|
||||||
}
|
|
||||||
|
|
||||||
c.setSectorIdentifierUri(getAsString(o, "sector_identifier_uri"));
|
|
||||||
|
|
||||||
String subjectType = getAsString(o, "subject_type");
|
|
||||||
if (subjectType != null) {
|
|
||||||
c.setSubjectType(SubjectType.getByValue(subjectType));
|
|
||||||
}
|
|
||||||
|
|
||||||
c.setRequestObjectSigningAlg(getAsJwsAlgorithm(o, "request_object_signing_alg"));
|
|
||||||
|
|
||||||
c.setUserInfoSignedResponseAlg(getAsJwsAlgorithm(o, "userinfo_signed_response_alg"));
|
|
||||||
c.setUserInfoEncryptedResponseAlg(getAsJweAlgorithm(o, "userinfo_encrypted_response_alg"));
|
|
||||||
c.setUserInfoEncryptedResponseEnc(getAsJweEncryptionMethod(o, "userinfo_encrypted_response_enc"));
|
|
||||||
|
|
||||||
c.setIdTokenSignedResponseAlg(getAsJwsAlgorithm(o, "id_token_signed_response_alg"));
|
|
||||||
c.setIdTokenEncryptedResponseAlg(getAsJweAlgorithm(o, "id_token_encrypted_response_alg"));
|
|
||||||
c.setIdTokenEncryptedResponseEnc(getAsJweEncryptionMethod(o, "id_token_encrypted_response_enc"));
|
|
||||||
|
|
||||||
if (o.has("default_max_age")) {
|
|
||||||
if (o.get("default_max_age").isJsonPrimitive()) {
|
|
||||||
c.setDefaultMaxAge(o.get("default_max_age").getAsInt());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (o.has("require_auth_time")) {
|
|
||||||
if (o.get("require_auth_time").isJsonPrimitive()) {
|
|
||||||
c.setRequireAuthTime(o.get("require_auth_time").getAsBoolean());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.setDefaultACRvalues(getAsStringSet(o, "default_acr_values"));
|
|
||||||
c.setInitiateLoginUri(getAsString(o, "initiate_login_uri"));
|
|
||||||
c.setPostLogoutRedirectUri(getAsString(o, "post_logout_redirect_uri"));
|
|
||||||
c.setRequestUris(getAsStringSet(o, "request_uris"));
|
|
||||||
|
|
||||||
return c;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the value of the given given member as a set of strings, null if it doesn't exist
|
|
||||||
*/
|
|
||||||
private Set<String> getAsStringSet(JsonObject o, String member) throws JsonSyntaxException {
|
|
||||||
if (o.has(member)) {
|
|
||||||
return gson.fromJson(o.get(member), new TypeToken<Set<String>>(){}.getType());
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the value of the given member as a string, null if it doesn't exist
|
|
||||||
*/
|
|
||||||
private String getAsString(JsonObject o, String member) {
|
|
||||||
if (o.has(member)) {
|
|
||||||
JsonElement e = o.get(member);
|
|
||||||
if (e != null && e.isJsonPrimitive()) {
|
|
||||||
return e.getAsString();
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the value of the given member as a JWS Algorithm, null if it doesn't exist
|
|
||||||
*/
|
|
||||||
private JWSAlgorithmEmbed getAsJwsAlgorithm(JsonObject o, String member) {
|
|
||||||
String s = getAsString(o, member);
|
|
||||||
if (s != null) {
|
|
||||||
return JWSAlgorithmEmbed.getForAlgorithmName(s);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the value of the given member as a JWE Algorithm, null if it doesn't exist
|
|
||||||
*/
|
|
||||||
private JWEAlgorithmEmbed getAsJweAlgorithm(JsonObject o, String member) {
|
|
||||||
String s = getAsString(o, member);
|
|
||||||
if (s != null) {
|
|
||||||
return JWEAlgorithmEmbed.getForAlgorithmName(s);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the value of the given member as a JWE Encryption Method, null if it doesn't exist
|
|
||||||
*/
|
|
||||||
private JWEEncryptionMethodEmbed getAsJweEncryptionMethod(JsonObject o, String member) {
|
|
||||||
String s = getAsString(o, member);
|
|
||||||
if (s != null) {
|
|
||||||
return JWEEncryptionMethodEmbed.getForAlgorithmName(s);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @param client
|
* @param client
|
||||||
* @return
|
* @return
|
||||||
* @throws AuthenticationException
|
* @throws AuthenticationException
|
||||||
*/
|
*/
|
||||||
private OAuth2AccessTokenEntity createRegistrationAccessToken(ClientDetailsEntity client) throws AuthenticationException {
|
private OAuth2AccessTokenEntity createRegistrationAccessToken(ClientDetailsEntity client) throws AuthenticationException, InvalidClientException {
|
||||||
// create a registration access token, treat it like a client credentials flow
|
// create a registration access token, treat it like a client credentials flow
|
||||||
// I can't use the auth request interface here because it has no setters and bad constructors -- THIS IS BAD API DESIGN
|
// I can't use the auth request interface here because it has no setters and bad constructors -- THIS IS BAD API DESIGN
|
||||||
DefaultAuthorizationRequest authorizationRequest = new DefaultAuthorizationRequest(client.getClientId(), Sets.newHashSet(OAuth2AccessTokenEntity.REGISTRATION_TOKEN_SCOPE));
|
DefaultAuthorizationRequest authorizationRequest = new DefaultAuthorizationRequest(client.getClientId(), Sets.newHashSet(OAuth2AccessTokenEntity.REGISTRATION_TOKEN_SCOPE));
|
||||||
|
@ -463,4 +180,208 @@ public class ClientDynamicRegistrationEndpoint {
|
||||||
return registrationAccessToken;
|
return registrationAccessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasRole('ROLE_CLIENT') and #oauth2.hasScope('registration-token')")
|
||||||
|
@RequestMapping(params = "operation=rotate_secret", produces = "application/json")
|
||||||
|
public String rotateSecret(OAuth2Authentication auth, ModelMap model) {
|
||||||
|
|
||||||
|
|
||||||
|
String clientId = auth.getAuthorizationRequest().getClientId();
|
||||||
|
ClientDetailsEntity client = clientService.loadClientByClientId(clientId);
|
||||||
|
|
||||||
|
if (client == null) {
|
||||||
|
throw new ClientNotFoundException("Could not find client: " + clientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rotate the secret, if available
|
||||||
|
if (client.isSecretRequired()) {
|
||||||
|
client = clientService.generateClientSecret(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
OAuth2AccessTokenEntity registrationAccessToken = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// mint a new access token
|
||||||
|
registrationAccessToken = createRegistrationAccessToken(client);
|
||||||
|
} catch (AuthenticationException e) {
|
||||||
|
//TODO: Error Handling
|
||||||
|
//AuthException may be handled by spring security
|
||||||
|
}
|
||||||
|
|
||||||
|
// revoke the old one
|
||||||
|
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) auth.getDetails();
|
||||||
|
if (details != null) {
|
||||||
|
OAuth2AccessTokenEntity oldAccessToken = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
oldAccessToken = tokenService.readAccessToken(details.getTokenValue());
|
||||||
|
} catch (AuthenticationException e) {
|
||||||
|
//TODO: Error Handling
|
||||||
|
} catch (InvalidTokenException e) {
|
||||||
|
//TODO: Error Handling
|
||||||
|
}
|
||||||
|
if (oldAccessToken != null) {
|
||||||
|
tokenService.revokeAccessToken(oldAccessToken);
|
||||||
|
} else {
|
||||||
|
// serious error here -- how'd we get this far without a valid token?!
|
||||||
|
throw new OAuth2Exception("SEVERE: token not found, something is fishy");
|
||||||
|
//TODO: Error Handling
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// save the client
|
||||||
|
ClientDetailsEntity saved = clientService.updateClient(client, client);
|
||||||
|
|
||||||
|
model.put("fullClient", Boolean.FALSE);
|
||||||
|
model.put("client", saved);
|
||||||
|
model.put("token", registrationAccessToken);
|
||||||
|
|
||||||
|
return "clientRegistration";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasRole('ROLE_CLIENT') and #oauth2.hasScope('registration-token')")
|
||||||
|
@RequestMapping(params = "operation=client_update", produces = "application/json")
|
||||||
|
public String clientUpdate(
|
||||||
|
@RequestParam(value = "redirect_uris", required = true) Set<String> redirectUris,
|
||||||
|
@RequestParam(value = "client_name", required = false) String clientName,
|
||||||
|
@RequestParam(value = "client_url", required = false) String clientUrl,
|
||||||
|
@RequestParam(value = "logo_url", required = false) String logoUrl,
|
||||||
|
@RequestParam(value = "contacts", required = false) Set<String> contacts,
|
||||||
|
@RequestParam(value = "tos_url", required = false) String tosUrl,
|
||||||
|
@RequestParam(value = "token_endpoint_auth_method", required = false) AuthMethod tokenEndpointAuthMethod,
|
||||||
|
@RequestParam(value = "policy_url", required = false) String policyUrl,
|
||||||
|
|
||||||
|
@RequestParam(value = "scope", required = false) Set<String> scope,
|
||||||
|
@RequestParam(value = "grant_type", required = false) Set<String> grantType,
|
||||||
|
|
||||||
|
@RequestParam(value = "jwk_url", required = false) String jwkUrl,
|
||||||
|
@RequestParam(value = "jwk_encryption_url", required = false) String jwkEncryptionUrl,
|
||||||
|
@RequestParam(value = "x509_url", required = false) String x509Url,
|
||||||
|
@RequestParam(value = "x509_encryption_url", required = false) String x509EncryptionUrl,
|
||||||
|
@RequestParam(value = "default_max_age", required = false) Integer defaultMaxAge,
|
||||||
|
@RequestParam(value = "default_acr", required = false) String defaultAcr,
|
||||||
|
|
||||||
|
// OPENID CONNECT EXTENSIONS BELOW
|
||||||
|
@RequestParam(value = "application_type", required = false) AppType applicationType,
|
||||||
|
@RequestParam(value = "sector_identifier_url", required = false) String sectorIdentifierUrl,
|
||||||
|
@RequestParam(value = "subject_type", required = false) SubjectType subjectType,
|
||||||
|
@RequestParam(value = "require_signed_request_object", required = false) JWSAlgorithm requireSignedRequestObject,
|
||||||
|
@RequestParam(value = "require_auth_time", required = false, defaultValue = "true") Boolean requireAuthTime,
|
||||||
|
// TODO: JWE needs to be handled properly, see @InitBinder above -- we'll ignore these right now
|
||||||
|
/*
|
||||||
|
@RequestParam(value = "userinfo_signed_response_alg", required = false) String userinfoSignedResponseAlg,
|
||||||
|
@RequestParam(value = "userinfo_encrypted_response_alg", required = false) String userinfoEncryptedResponseAlg,
|
||||||
|
@RequestParam(value = "userinfo_encrypted_response_enc", required = false) String userinfoEncryptedResponseEnc,
|
||||||
|
@RequestParam(value = "userinfo_encrypted_response_int", required = false) String userinfoEncryptedResponseInt,
|
||||||
|
@RequestParam(value = "idtoken_signed_response_alg", required = false) String idtokenSignedResponseAlg,
|
||||||
|
@RequestParam(value = "idtoken_encrypted_response_alg", required = false) String idtokenEncryptedResponseAlg,
|
||||||
|
@RequestParam(value = "idtoken_encrypted_response_enc", required = false) String idtokenEncryptedResponseEnc,
|
||||||
|
@RequestParam(value = "idtoken_encrypted_response_int", required = false) String idtokenEncryptedResponseInt,
|
||||||
|
*/
|
||||||
|
|
||||||
|
@RequestParam Map<String, String> params,
|
||||||
|
|
||||||
|
OAuth2Authentication auth,
|
||||||
|
ModelMap model
|
||||||
|
|
||||||
|
) {
|
||||||
|
|
||||||
|
String clientId = auth.getAuthorizationRequest().getClientId();
|
||||||
|
ClientDetailsEntity client = clientService.loadClientByClientId(clientId);
|
||||||
|
|
||||||
|
if (client == null) {
|
||||||
|
throw new ClientNotFoundException("Could not find client: " + clientId);
|
||||||
|
//TODO: Error Handling
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* now process each field:
|
||||||
|
* 1) If input is not provided (null, not in map), keep existing value
|
||||||
|
* 2) If input is provided (in map) but null or blank, remove existing value
|
||||||
|
* 3) If input is not null and not blank, replace existing value
|
||||||
|
*/
|
||||||
|
if (params.containsKey("contacts")) {
|
||||||
|
client.setContacts(contacts);
|
||||||
|
}
|
||||||
|
if (params.containsKey("application_type")) {
|
||||||
|
client.setApplicationType(applicationType);
|
||||||
|
}
|
||||||
|
if (params.containsKey("client_name")) {
|
||||||
|
client.setClientName(Strings.emptyToNull(clientName));
|
||||||
|
}
|
||||||
|
if (params.containsKey("client_url")) {
|
||||||
|
client.setClientUrl(Strings.emptyToNull(clientUrl));
|
||||||
|
}
|
||||||
|
if (params.containsKey("tos_url")) {
|
||||||
|
client.setTosUrl(Strings.emptyToNull(tosUrl));
|
||||||
|
}
|
||||||
|
if (params.containsKey("logo_url")) {
|
||||||
|
client.setLogoUrl(Strings.emptyToNull(logoUrl));
|
||||||
|
}
|
||||||
|
if (params.containsKey("redirect_uris")) {
|
||||||
|
client.setRegisteredRedirectUri(redirectUris);
|
||||||
|
}
|
||||||
|
if (params.containsKey("token_endpoint_auth_method")) {
|
||||||
|
client.setTokenEndpointAuthMethod(tokenEndpointAuthMethod);
|
||||||
|
}
|
||||||
|
if (params.containsKey("policy_url")) {
|
||||||
|
client.setPolicyUrl(Strings.emptyToNull(policyUrl));
|
||||||
|
}
|
||||||
|
if (params.containsKey("jwk_url")) {
|
||||||
|
client.setJwkUrl(Strings.emptyToNull(jwkUrl));
|
||||||
|
}
|
||||||
|
if (params.containsKey("jwk_encryption_url")) {
|
||||||
|
client.setJwkEncryptionUrl(Strings.emptyToNull(jwkEncryptionUrl));
|
||||||
|
}
|
||||||
|
if (params.containsKey("x509_url")) {
|
||||||
|
client.setX509Url(Strings.emptyToNull(x509Url));
|
||||||
|
}
|
||||||
|
if (params.containsKey("x509_encryption_url")) {
|
||||||
|
client.setX509EncryptionUrl(Strings.emptyToNull(x509EncryptionUrl));
|
||||||
|
}
|
||||||
|
if (params.containsKey("default_max_age")) {
|
||||||
|
client.setDefaultMaxAge(defaultMaxAge);
|
||||||
|
}
|
||||||
|
if (params.containsKey("default_acr")) {
|
||||||
|
client.setDefaultACR(Strings.emptyToNull(defaultAcr));
|
||||||
|
}
|
||||||
|
if (params.containsKey("scope")) {
|
||||||
|
// set of scopes that are OK for clients to dynamically register for
|
||||||
|
Set<SystemScope> dynScopes = scopeService.getDynReg();
|
||||||
|
|
||||||
|
// scopes that the client is asking for
|
||||||
|
Set<SystemScope> requestedScopes = scopeService.fromStrings(scope);
|
||||||
|
|
||||||
|
// the scopes that the client can have must be a subset of the dynamically allowed scopes
|
||||||
|
Set<SystemScope> allowedScopes = Sets.intersection(dynScopes, requestedScopes);
|
||||||
|
|
||||||
|
client.setScope(scopeService.toStrings(allowedScopes));
|
||||||
|
}
|
||||||
|
if (params.containsKey("grant_type")) {
|
||||||
|
// TODO: check against some kind of grant type service for validity
|
||||||
|
client.setAuthorizedGrantTypes(grantType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// OIDC
|
||||||
|
if (params.containsKey("sector_identifier_url")) {
|
||||||
|
client.setSectorIdentifierUrl(Strings.emptyToNull(sectorIdentifierUrl));
|
||||||
|
}
|
||||||
|
if (params.containsKey("subject_type")) {
|
||||||
|
client.setSubjectType(subjectType);
|
||||||
|
}
|
||||||
|
if (params.containsKey("require_signed_request_object")) { // TODO: rename field
|
||||||
|
client.setRequireSignedRequestObject(new JWSAlgorithmEntity(requireSignedRequestObject));
|
||||||
|
}
|
||||||
|
if (params.containsKey("require_auth_time")) {
|
||||||
|
client.setRequireAuthTime(requireAuthTime == null ? false : requireAuthTime.booleanValue()); // watch out for autoboxing
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ClientDetailsEntity saved = clientService.updateClient(client, client);
|
||||||
|
|
||||||
|
model.put("fullClient", Boolean.TRUE);
|
||||||
|
model.put("client", saved);
|
||||||
|
return "clientRegister";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,9 +60,9 @@ public class UserInfoEndpoint {
|
||||||
/**
|
/**
|
||||||
* Get information about the user as specified in the accessToken->idToken included in this request
|
* Get information about the user as specified in the accessToken->idToken included in this request
|
||||||
*
|
*
|
||||||
* @throws UserNotFoundException if the user does not exist or cannot be found
|
* @throws UserNotFoundException if the user does not exist or cannot be found
|
||||||
* @throws UnknownUserInfoSchemaException if an unknown schema is used
|
* @throws UnknownUserInfoSchemaException if an unknown schema is used
|
||||||
* @throws InvalidScopeException if the oauth2 token doesn't have the "openid" scope
|
* @throws InvalidScopeException if the oauth2 token doesn't have the "openid" scope
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("hasRole('ROLE_USER') and #oauth2.hasScope('openid')")
|
@PreAuthorize("hasRole('ROLE_USER') and #oauth2.hasScope('openid')")
|
||||||
@RequestMapping(value="/userinfo", method= {RequestMethod.GET, RequestMethod.POST}, produces = "application/json")
|
@RequestMapping(value="/userinfo", method= {RequestMethod.GET, RequestMethod.POST}, produces = "application/json")
|
||||||
|
@ -70,11 +70,13 @@ public class UserInfoEndpoint {
|
||||||
|
|
||||||
if (p == null) {
|
if (p == null) {
|
||||||
throw new UserNotFoundException("Invalid User");
|
throw new UserNotFoundException("Invalid User");
|
||||||
|
//TODO: Error Handling
|
||||||
}
|
}
|
||||||
|
|
||||||
String viewName = schemaToViewNameMap.get(schema);
|
String viewName = schemaToViewNameMap.get(schema);
|
||||||
if (viewName == null) {
|
if (viewName == null) {
|
||||||
throw new UnknownUserInfoSchemaException("Unknown User Info Schema: " + schema );
|
throw new UnknownUserInfoSchemaException("Unknown User Info Schema: " + schema );
|
||||||
|
//TODO: Error Handling
|
||||||
}
|
}
|
||||||
|
|
||||||
String userId = p.getName();
|
String userId = p.getName();
|
||||||
|
@ -82,6 +84,7 @@ public class UserInfoEndpoint {
|
||||||
|
|
||||||
if (userInfo == null) {
|
if (userInfo == null) {
|
||||||
throw new UserNotFoundException("User not found: " + userId);
|
throw new UserNotFoundException("User not found: " + userId);
|
||||||
|
//TODO: Error Handling
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p instanceof OAuth2Authentication) {
|
if (p instanceof OAuth2Authentication) {
|
||||||
|
@ -93,8 +96,6 @@ public class UserInfoEndpoint {
|
||||||
|
|
||||||
model.addAttribute("userInfo", userInfo);
|
model.addAttribute("userInfo", userInfo);
|
||||||
|
|
||||||
//return new ModelAndView(viewName, "userInfo", userInfo);
|
|
||||||
|
|
||||||
return viewName;
|
return viewName;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,9 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author jricher
|
* @author jricher
|
||||||
|
@ -63,10 +65,19 @@ public class WhitelistAPI {
|
||||||
@RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
|
@RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
|
||||||
public String addNewWhitelistedSite(@RequestBody String jsonString, ModelMap m, Principal p) {
|
public String addNewWhitelistedSite(@RequestBody String jsonString, ModelMap m, Principal p) {
|
||||||
|
|
||||||
JsonObject json = parser.parse(jsonString).getAsJsonObject();
|
JsonObject json;
|
||||||
|
|
||||||
WhitelistedSite whitelist = gson.fromJson(json, WhitelistedSite.class);
|
WhitelistedSite whitelist = null;
|
||||||
|
try {
|
||||||
|
json = parser.parse(jsonString).getAsJsonObject();
|
||||||
|
whitelist = gson.fromJson(json, WhitelistedSite.class);
|
||||||
|
|
||||||
|
} catch (JsonParseException e) {
|
||||||
|
//TODO: Error Handling
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// save the id of the person who created this
|
// save the id of the person who created this
|
||||||
whitelist.setCreatorUserId(p.getName());
|
whitelist.setCreatorUserId(p.getName());
|
||||||
|
|
||||||
|
@ -85,9 +96,18 @@ public class WhitelistAPI {
|
||||||
@RequestMapping(value="/{id}", method = RequestMethod.PUT, consumes = "application/json", produces = "application/json")
|
@RequestMapping(value="/{id}", method = RequestMethod.PUT, consumes = "application/json", produces = "application/json")
|
||||||
public String updateWhitelistedSite(@PathVariable("id") Long id, @RequestBody String jsonString, ModelMap m, Principal p) {
|
public String updateWhitelistedSite(@PathVariable("id") Long id, @RequestBody String jsonString, ModelMap m, Principal p) {
|
||||||
|
|
||||||
JsonObject json = parser.parse(jsonString).getAsJsonObject();
|
JsonObject json;
|
||||||
|
|
||||||
WhitelistedSite whitelist = gson.fromJson(json, WhitelistedSite.class);
|
WhitelistedSite whitelist = null;
|
||||||
|
try {
|
||||||
|
json = parser.parse(jsonString).getAsJsonObject();
|
||||||
|
whitelist = gson.fromJson(json, WhitelistedSite.class);
|
||||||
|
|
||||||
|
} catch (JsonParseException e) {
|
||||||
|
//TODO: Error Handling
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
WhitelistedSite oldWhitelist = whitelistService.getById(id);
|
WhitelistedSite oldWhitelist = whitelistService.getById(id);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue