Skip to content

Commit

Permalink
add validations and extension point
Browse files Browse the repository at this point in the history
  • Loading branch information
Yoshani committed Aug 2, 2023
1 parent bf6b1a1 commit 2ca830e
Show file tree
Hide file tree
Showing 14 changed files with 406 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
import org.wso2.carbon.identity.oauth2.scopeservice.ScopeMetadataService;
import org.wso2.carbon.identity.oauth2.token.bindings.TokenBinder;
import org.wso2.carbon.identity.oauth2.util.OAuth2Util;
import org.wso2.carbon.identity.oauth2.util.RequestUtil;
import org.wso2.carbon.identity.oidc.session.OIDCSessionState;
import org.wso2.carbon.identity.oidc.session.util.OIDCSessionManagementUtil;
import org.wso2.carbon.identity.openidconnect.OIDCConstants;
Expand Down Expand Up @@ -280,11 +281,15 @@ public Response authorize(@Context HttpServletRequest request, @Context HttpServ

// Using a separate try-catch block as this next try block has operations in the final block.
try {
request = RequestUtil.buildRequest(request);
oAuthMessage = buildOAuthMessage(request, response);

} catch (InvalidRequestParentException e) {
EndpointUtil.triggerOnAuthzRequestException(e, request);
throw e;
} catch (OAuthProblemException e) {
EndpointUtil.triggerOnAuthzRequestException(e, request);
throw new InvalidRequestException(e.getMessage(), OAuth2ErrorCodes.INVALID_REQUEST);
}

try {
Expand Down Expand Up @@ -1955,7 +1960,7 @@ private String handleOAuthAuthorizationRequest(OAuthMessage oAuthMessage)
setSPAttributeToRequest(oAuthMessage.getRequest(), validationResponse.getApplicationName(), tenantDomain);
}

OAuthAuthzRequest oauthRequest = getOAuthAuthzRequest(oAuthMessage.getRequest());
OAuthAuthzRequest oauthRequest = EndpointUtil.getOAuthAuthzRequest(oAuthMessage.getRequest());

OAuth2Parameters params = new OAuth2Parameters();
String sessionDataKey = UUID.randomUUID().toString();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
Expand All @@ -22,11 +22,13 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.cxf.interceptor.InInterceptors;
import org.apache.oltu.oauth2.common.error.OAuthError;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.json.JSONObject;
import org.wso2.carbon.identity.oauth.client.authn.filter.OAuthClientAuthenticatorProxy;
import org.wso2.carbon.identity.oauth.common.OAuth2ErrorCodes;
import org.wso2.carbon.identity.oauth.common.OAuthConstants;
import org.wso2.carbon.identity.oauth.common.exception.InvalidOAuthRequestException;
import org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil;
import org.wso2.carbon.identity.oauth.par.common.ParConstants;
import org.wso2.carbon.identity.oauth.par.exceptions.ParClientException;
Expand All @@ -51,6 +53,7 @@
import javax.ws.rs.core.Response;

import static org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil.getOAuth2Service;
import static org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil.validateParams;

/**
* REST implementation for OAuth2 PAR endpoint.
Expand Down Expand Up @@ -141,17 +144,12 @@ private Response handleParCoreException(ParCoreException parCoreException) {
}

private void handleValidation(HttpServletRequest request, MultivaluedMap<String, String> params)
throws ParClientException {
throws ParCoreException {

OAuth2ClientValidationResponseDTO validationResponse = getOAuth2Service().validateClientInfo(request);

if (!validationResponse.isValidClient()) {
throw new ParClientException(validationResponse.getErrorCode(), validationResponse.getErrorMsg());
}
if (isRequestUriProvided(params)) {
throw new ParClientException(OAuth2ErrorCodes.INVALID_REQUEST,
ParConstants.REQUEST_URI_IN_REQUEST_BODY_ERROR);
}
validateInputParameters(request);
validateClient(request, params);
validateRepeatedParams(request, params);
validateAuthzRequest(request);
}

private boolean isRequestUriProvided(MultivaluedMap<String, String> params) {
Expand All @@ -169,6 +167,10 @@ private void checkClientAuthentication(HttpServletRequest request) throws ParCor
if (OAuth2ErrorCodes.SERVER_ERROR.equals(oAuthClientAuthnContext.getErrorCode())) {
throw new ParCoreException(oAuthClientAuthnContext.getErrorCode(),
oAuthClientAuthnContext.getErrorMessage());
} else if (OAuth2ErrorCodes.INVALID_CLIENT.equals(oAuthClientAuthnContext.getErrorCode())) {
throw new ParClientException(oAuthClientAuthnContext.getErrorCode(),
"A valid OAuth client could not be found for client_id: " +
oAuthClientAuthnContext.getClientId());
}
throw new ParClientException(oAuthClientAuthnContext.getErrorCode(),
oAuthClientAuthnContext.getErrorMessage());
Expand All @@ -191,7 +193,50 @@ private OAuthClientAuthnContext createNewOAuthClientAuthnContext() {
OAuthClientAuthnContext oAuthClientAuthnContext = new OAuthClientAuthnContext();
oAuthClientAuthnContext.setAuthenticated(false);
oAuthClientAuthnContext.setErrorMessage(PAR_CLIENT_AUTH_ERROR);
oAuthClientAuthnContext.setErrorCode(OAuthError.TokenResponse.INVALID_REQUEST);
oAuthClientAuthnContext.setErrorCode(OAuth2ErrorCodes.INVALID_REQUEST);
return oAuthClientAuthnContext;
}

private void validateClient(HttpServletRequest request, MultivaluedMap<String, String> params)
throws ParClientException {

OAuth2ClientValidationResponseDTO validationResponse = getOAuth2Service().validateClientInfo(request);

if (!validationResponse.isValidClient()) {
throw new ParClientException(validationResponse.getErrorCode(),
"Cannot find an application associated with the given consumer key.");
}
if (isRequestUriProvided(params)) {
throw new ParClientException(OAuth2ErrorCodes.INVALID_REQUEST,
ParConstants.REQUEST_URI_IN_REQUEST_BODY_ERROR);
}
}

private void validateRepeatedParams(HttpServletRequest request, Map<String, List<String>> paramMap)
throws ParClientException {

if (!validateParams(request, paramMap)) {
throw new ParClientException(OAuth2ErrorCodes.INVALID_REQUEST, "Invalid request with repeated parameters.");
}
}

private void validateAuthzRequest(HttpServletRequest request) throws ParCoreException {

try {
EndpointUtil.getOAuthAuthzRequest(request);
} catch (OAuthProblemException e) {
throw new ParClientException(e.getError(), e.getDescription());
} catch (OAuthSystemException e) {
throw new ParCoreException(OAuth2ErrorCodes.SERVER_ERROR, e.getMessage());
}
}

private void validateInputParameters(HttpServletRequest request) throws ParClientException {

try {
getOAuth2Service().validateInputParameters(request);
} catch (InvalidOAuthRequestException e) {
throw new ParClientException(e.getErrorCode(), e.getMessage());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.apache.commons.logging.LogFactory;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URIBuilder;
import org.apache.oltu.oauth2.as.request.OAuthAuthzRequest;
import org.apache.oltu.oauth2.as.response.OAuthASResponse;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
Expand Down Expand Up @@ -93,6 +94,7 @@
import org.wso2.carbon.identity.oauth2.bean.OAuthClientAuthnContext;
import org.wso2.carbon.identity.oauth2.bean.Scope;
import org.wso2.carbon.identity.oauth2.dto.OAuth2ClientValidationResponseDTO;
import org.wso2.carbon.identity.oauth2.model.CarbonOAuthAuthzRequest;
import org.wso2.carbon.identity.oauth2.model.OAuth2Parameters;
import org.wso2.carbon.identity.oauth2.model.OAuth2ScopeConsentResponse;
import org.wso2.carbon.identity.oauth2.scopeservice.OAuth2Resource;
Expand All @@ -110,6 +112,8 @@
import java.io.IOException;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.ArrayList;
Expand Down Expand Up @@ -167,6 +171,7 @@ public class EndpointUtil {
private static IdpManager idpManager;
private static final String ALLOW_ADDITIONAL_PARAMS_FROM_ERROR_URL = "OAuth.AllowAdditionalParamsFromErrorUrl";
private static final String IDP_ENTITY_ID = "IdPEntityId";
private static Class<? extends OAuthAuthzRequest> oAuthAuthzRequestClass;

public static void setIdpManager(IdpManager idpManager) {

Expand Down Expand Up @@ -1804,4 +1809,57 @@ public static boolean isExternalConsentPageEnabledForSP(ServiceProvider serviceP
public static boolean isConsentPageRedirectParamsAllowed() {
return FileBasedConfigurationBuilder.getInstance().isConsentPageRedirectParamsAllowed();
}

public static OAuthAuthzRequest getOAuthAuthzRequest(HttpServletRequest request)
throws OAuthProblemException, OAuthSystemException {

OAuthAuthzRequest oAuthAuthzRequest;

if (isDefaultOAuthAuthzRequestClassConfigured()) {
oAuthAuthzRequest = new CarbonOAuthAuthzRequest(request);
} else {
try {
Class<? extends OAuthAuthzRequest> clazz = getOAuthAuthzRequestClass();
// Validations will be performed when initializing the class instance.
Constructor<?> constructor = clazz.getConstructor(HttpServletRequest.class);
oAuthAuthzRequest = (OAuthAuthzRequest) constructor.newInstance(request);
} catch (InvocationTargetException e) {
// Handle OAuthProblemException & OAuthSystemException thrown from extended class.
if (e.getTargetException() instanceof OAuthProblemException) {
throw (OAuthProblemException) e.getTargetException();
} else if (e.getTargetException() instanceof OAuthSystemException) {
throw (OAuthSystemException) e.getTargetException();
} else {
log.warn("Failed to initiate OAuthAuthzRequest from identity.xml. " +
"Hence initiating the default implementation");
oAuthAuthzRequest = new CarbonOAuthAuthzRequest(request);
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException |
NoSuchMethodException e) {
log.warn("Failed to initiate OAuthAuthzRequest from identity.xml. " +
"Hence initiating the default implementation");
oAuthAuthzRequest = new CarbonOAuthAuthzRequest(request);
}
}
return oAuthAuthzRequest;
}

private static boolean isDefaultOAuthAuthzRequestClassConfigured() {

String oauthAuthzRequestClassName = OAuthServerConfiguration.getInstance().getOAuthAuthzRequestClassName();
return OAuthServerConfiguration.DEFAULT_OAUTH_AUTHZ_REQUEST_CLASSNAME.equals(oauthAuthzRequestClassName);
}

private static Class<? extends OAuthAuthzRequest> getOAuthAuthzRequestClass() throws ClassNotFoundException {

if (oAuthAuthzRequestClass == null) {

String oauthAuthzRequestClassName =
OAuthServerConfiguration.getInstance().getOAuthAuthzRequestClassName();
oAuthAuthzRequestClass = (Class<? extends OAuthAuthzRequest>) Thread.currentThread()
.getContextClassLoader().loadClass(oauthAuthzRequestClassName);

}
return oAuthAuthzRequestClass;
}
}
6 changes: 5 additions & 1 deletion components/org.wso2.carbon.identity.oauth.par/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@
<groupId>org.wso2.carbon.identity.inbound.auth.oauth2</groupId>
<artifactId>org.wso2.carbon.identity.oauth.common</artifactId>
</dependency>

<dependency>
<groupId>org.wso2.carbon.identity.inbound.auth.oauth2</groupId>
<artifactId>org.wso2.carbon.identity.oauth</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon.identity.framework</groupId>
<artifactId>org.wso2.carbon.identity.application.mgt</artifactId>
Expand Down Expand Up @@ -114,6 +117,7 @@
org.apache.commons.lang; version="${commons-lang.wso2.osgi.version.range}",
org.wso2.carbon.identity.oauth.common.*;version="${identity.inbound.auth.oauth.exp.pkg.version}"
org.apache.oltu.oauth2.common.*; version="${oltu.package.import.version.range}",
org.wso2.carbon.identity.oauth2.*;version="${identity.inbound.auth.oauth.exp.pkg.version}",
org.osgi.framework; version="${osgi.framework.imp.pkg.version.range}",
org.osgi.service.component; version="${osgi.service.component.imp.pkg.version.range}",
org.wso2.carbon.identity.application.authentication.framework.cache; version="${carbon.identity.framework.imp.pkg.version.range}",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
*
* WSO2 LLC. licenses this file to you 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.wso2.carbon.identity.oauth.par.core;

import org.apache.commons.lang.StringUtils;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.wso2.carbon.identity.oauth.common.OAuthConstants;
import org.wso2.carbon.identity.oauth.par.model.OAuthParRequestWrapper;
import org.wso2.carbon.identity.oauth2.AbstractRequestBuilder;

import javax.servlet.http.HttpServletRequest;

/**
* This is a global level interface for building requests.
*/
public class ParRequestBuilder implements AbstractRequestBuilder {

private static final String REQUEST_BUILDER_NAME = "Pushed authorization request builder";

@Override
public HttpServletRequest buildRequest(HttpServletRequest request) throws OAuthProblemException {

return new OAuthParRequestWrapper(request);
}

@Override
public boolean canHandle(HttpServletRequest request) {

return StringUtils.isNotBlank(request.getParameter(OAuthConstants.OAuth20Params.REQUEST_URI));
}

@Override
public String getName() {

return REQUEST_BUILDER_NAME;
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
Expand All @@ -15,15 +15,16 @@
* specific language governing permissions and limitations
* under the License.
*/

package org.wso2.carbon.identity.oauth.par.internal;

import com.hazelcast.org.apache.hc.core5.http.support.AbstractRequestBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Component;
import org.wso2.carbon.identity.oauth.par.core.ParAuthService;
import org.wso2.carbon.identity.oauth.par.core.ParAuthServiceImpl;
import org.wso2.carbon.identity.oauth.par.core.ParRequestBuilder;

/**
* Service component for PAR.
Expand All @@ -41,6 +42,8 @@ protected void activate(ComponentContext context) {
try {
context.getBundleContext().registerService(ParAuthService.class.getName(),
new ParAuthServiceImpl(), null);
context.getBundleContext().registerService(AbstractRequestBuilder.class.getName(),
new ParRequestBuilder(), null);
log.debug("PAR component bundle is activated.");
} catch (Throwable e) {
log.error("Error occurred while activating PAR component.", e);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
Expand All @@ -20,10 +20,10 @@
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.wso2.carbon.identity.oauth.common.OAuthConstants;
import org.wso2.carbon.identity.oauth.par.common.ParConstants;
import org.wso2.carbon.identity.oauth.par.core.ParAuthService;
import org.wso2.carbon.identity.oauth.par.exceptions.ParAuthFailureException;
import org.wso2.carbon.identity.oauth.par.exceptions.ParClientException;
import org.wso2.carbon.identity.oauth.par.exceptions.ParCoreException;
import org.wso2.carbon.identity.oauth.par.util.ParUtil;

import java.util.Map;

Expand All @@ -43,27 +43,23 @@ public class OAuthParRequestWrapper extends HttpServletRequestWrapper {
* Wraps the request with parameters obtained from the PAR endpoint.
*
* @param request HttpServletRequest.
* @param parAuthService ParAuthService.
* @throws OAuthProblemException OAuthProblemException.
*/
public OAuthParRequestWrapper(HttpServletRequest request, ParAuthService parAuthService)
public OAuthParRequestWrapper(HttpServletRequest request)
throws OAuthProblemException {

super(request);

//get only uuid from request_uri
// Get only uuid from request_uri.
String requestUri = request.getParameter(OAuthConstants.OAuth20Params.REQUEST_URI);
String uuid = requestUri.replaceFirst(ParConstants.REQUEST_URI_PREFIX, "");

try {
if (parAuthService == null) {
throw new ParAuthFailureException("ParAuthService is not initialized properly");
}

params = parAuthService.retrieveParams(uuid,
request.getParameter(OAuthConstants.OAuth20Params.CLIENT_ID));
params = ParUtil.getParAuthService()
.retrieveParams(uuid, request.getParameter(OAuthConstants.OAuth20Params.CLIENT_ID));
params.put(OAuthConstants.ALLOW_REQUEST_URI_AND_REQUEST_OBJECT_IN_REQUEST, "true");
// set request_uri to empty string to avoid conflicting with OIDC flow
// Set request_uri to empty string to avoid conflicting with OIDC flow.
params.put(OAuthConstants.OAuth20Params.REQUEST_URI, "");
} catch (ParClientException e) {
throw new ParAuthFailureException(e.getMessage());
Expand Down
Loading

0 comments on commit 2ca830e

Please sign in to comment.