diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/pom.xml b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/pom.xml
index 2d2ba8214b..5cb2b2a9b0 100644
--- a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/pom.xml
+++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/pom.xml
@@ -86,6 +86,7 @@
org.wso2.carbon.utils,
org.wso2.carbon.utils.multitenancy,
org.xml.sax,
+ com.google.gson.*,
javax.servlet,
javax.servlet.http,
javax.xml,
@@ -215,6 +216,10 @@
org.wso2.carbon.devicemgt
org.wso2.carbon.device.mgt.common
+
+ com.google.code.gson
+ gson
+
org.wso2.orbit.org.apache.httpcomponents
httpclient
diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/AuthenticationFrameworkUtil.java b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/AuthenticationFrameworkUtil.java
index f3e0a4fe88..7c506737e7 100644
--- a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/AuthenticationFrameworkUtil.java
+++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/AuthenticationFrameworkUtil.java
@@ -22,6 +22,13 @@ import org.apache.catalina.connector.Response;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
+import org.wso2.carbon.base.MultitenantConstants;
+import org.wso2.carbon.context.PrivilegedCarbonContext;
+import org.wso2.carbon.user.api.UserRealm;
+import org.wso2.carbon.user.api.UserStoreException;
+import org.wso2.carbon.user.core.service.RealmService;
+import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
+import org.wso2.carbon.webapp.authenticator.framework.internal.AuthenticatorFrameworkDataHolder;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
@@ -32,6 +39,7 @@ import java.io.IOException;
public class AuthenticationFrameworkUtil {
private static final Log log = LogFactory.getLog(AuthenticationFrameworkUtil.class);
+ private static final String UI_EXECUTE = "ui.execute";
static void handleResponse(Request request, Response response, int statusCode, String payload) {
response.setStatus(statusCode);
@@ -65,4 +73,43 @@ public class AuthenticationFrameworkUtil {
}
}
+ static boolean isUserAuthorized(int tenantId, String tenantDomain, String username, String
+ permission) throws
+ AuthenticationException {
+ boolean tenantFlowStarted = false;
+
+ try{
+ //If this is a tenant user
+ if(tenantId != MultitenantConstants.SUPER_TENANT_ID){
+ PrivilegedCarbonContext.startTenantFlow();
+ PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain);
+ PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(tenantId);
+ PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(username);
+ tenantFlowStarted = true;
+ }
+
+ RealmService realmService = AuthenticatorFrameworkDataHolder.getInstance().getRealmService();
+ if (realmService == null) {
+ String msg = "RealmService is not initialized";
+ log.error(msg);
+ throw new AuthenticationException(msg);
+ }
+ UserRealm userRealm = realmService.getTenantUserRealm(tenantId);
+
+ return userRealm.getAuthorizationManager()
+ .isUserAuthorized(MultitenantUtils
+ .getTenantAwareUsername(username), permission, UI_EXECUTE);
+
+ } catch (UserStoreException e) {
+ String msg = "Error while getting username";
+ log.error(msg, e);
+ throw new AuthenticationException(msg, e);
+ }
+ finally {
+ if (tenantFlowStarted) {
+ PrivilegedCarbonContext.endTenantFlow();
+ }
+ }
+ }
+
}
diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/Constants.java b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/Constants.java
index af69a320ea..2694ea069a 100644
--- a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/Constants.java
+++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/Constants.java
@@ -22,7 +22,7 @@ public final class Constants {
public static final String AUTHORIZATION_HEADER_PREFIX_BEARER = "Bearer";
public static final String NO_MATCHING_AUTH_SCHEME = "noMatchedAuthScheme";
- public static final String PROXY_TENANT_ID = "ProxyTenantId";
+ public static final String PROXY_TENANT_ID = "Proxy-Tenant-Id";
public static final class HTTPHeaders {
private HTTPHeaders() {
diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValve.java b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValve.java
index 16bf4d695e..1370482cd2 100644
--- a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValve.java
+++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValve.java
@@ -18,9 +18,11 @@
*/
package org.wso2.carbon.webapp.authenticator.framework;
+import com.google.gson.Gson;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
+import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.owasp.encoder.Encode;
@@ -42,12 +44,15 @@ public class WebappAuthenticationValve extends CarbonTomcatValve {
private static final Log log = LogFactory.getLog(WebappAuthenticationValve.class);
private static TreeMap nonSecuredEndpoints = new TreeMap<>();
+ private static final String PERMISSION_PREFIX = "/permission/admin";
+ public static final String AUTHORIZE_PERMISSION = "Authorize-Permission";
@Override
public void invoke(Request request, Response response, CompositeValve compositeValve) {
- if (this.isContextSkipped(request) || this.skipAuthentication(request)) {
- this.getNext().invoke(request, response, compositeValve);
+ if ((this.isContextSkipped(request) || this.skipAuthentication(request))
+ && (StringUtils.isEmpty(request.getHeader(AUTHORIZE_PERMISSION)))) {
+ this.getNext().invoke(request, response, compositeValve);
return;
}
@@ -64,6 +69,39 @@ public class WebappAuthenticationValve extends CarbonTomcatValve {
authenticationInfo.setStatus(status);
}
+ // This section will allow to validate a given access token is authenticated to access given
+ // resource(permission)
+ if (request.getCoyoteRequest() != null
+ && StringUtils.isNotEmpty(request.getHeader(AUTHORIZE_PERMISSION))
+ && (authenticationInfo.getStatus() == WebappAuthenticator.Status.CONTINUE ||
+ authenticationInfo.getStatus() == WebappAuthenticator.Status.SUCCESS)) {
+ boolean isAllowed;
+ try {
+ isAllowed = AuthenticationFrameworkUtil.isUserAuthorized(
+ authenticationInfo.getTenantId(), authenticationInfo.getTenantDomain(),
+ authenticationInfo.getUsername(),
+ PERMISSION_PREFIX + request.getHeader (AUTHORIZE_PERMISSION));
+ } catch (AuthenticationException e) {
+ String msg = "Could not authorize permission";
+ log.error(msg);
+ AuthenticationFrameworkUtil.handleResponse(request, response,
+ HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg);
+ return;
+ }
+
+ if (isAllowed) {
+ Gson gson = new Gson();
+ AuthenticationFrameworkUtil.handleResponse(request, response, HttpServletResponse.SC_OK,
+ gson.toJson(authenticationInfo));
+ return;
+ } else {
+ log.error("Unauthorized message from user " + authenticationInfo.getUsername());
+ AuthenticationFrameworkUtil.handleResponse(request, response,
+ HttpServletResponse.SC_FORBIDDEN, "Unauthorized to access the API");
+ return;
+ }
+ }
+
Tenant tenant = null;
if (authenticationInfo.getTenantId() != -1) {
try {
@@ -72,7 +110,8 @@ public class WebappAuthenticationValve extends CarbonTomcatValve {
privilegedCarbonContext.setTenantId(authenticationInfo.getTenantId());
privilegedCarbonContext.setTenantDomain(authenticationInfo.getTenantDomain());
privilegedCarbonContext.setUsername(authenticationInfo.getUsername());
- if (authenticationInfo.isSuperTenantAdmin()) {
+ if (authenticationInfo.isSuperTenantAdmin() && request.getHeader(Constants
+ .PROXY_TENANT_ID) != null) {
// If this is a call from super admin to an API and the ProxyTenantId is also
// present, this is a call that is made with super admin credentials to call
// an API on behalf of another tenant. Hence the actual tenants, details are
diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValveTest.java b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValveTest.java
index 69cbac221a..91dfad24ca 100644
--- a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValveTest.java
+++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/test/java/org/wso2/carbon/webapp/authenticator/framework/WebappAuthenticationValveTest.java
@@ -55,8 +55,9 @@ public class WebappAuthenticationValveTest {
@Test(description = "This method tests the invoke method of the WebAppAuthenticationValve with the context path "
+ "starting with carbon")
- public void testInvokeWithContextSkippedScenario1() {
+ public void testInvokeWithContextSkippedScenario1() throws NoSuchFieldException, IllegalAccessException {
Request request = new Request();
+ getCoyoteRequest(request);
Context context = new StandardContext();
context.setPath("carbon");
CompositeValve compositeValve = Mockito.mock(CompositeValve.class);
@@ -64,6 +65,7 @@ public class WebappAuthenticationValveTest {
request.setContext(context);
webappAuthenticationValve.invoke(request, null, compositeValve);
request = new TestRequest("", "test");
+ getCoyoteRequest(request);
context = new StandardContext();
compositeValve = Mockito.mock(CompositeValve.class);
Mockito.doNothing().when(compositeValve).continueInvocation(Mockito.any(), Mockito.any());
@@ -73,8 +75,9 @@ public class WebappAuthenticationValveTest {
@Test(description = "This method tests the behaviour of the invoke method of WebAuthenticationValve when "
+ "un-secured endpoints are invoked.")
- public void testInvokeUnSecuredEndpoints() {
+ public void testInvokeUnSecuredEndpoints() throws IllegalAccessException, NoSuchFieldException {
Request request = new TestRequest("", "test");
+ getCoyoteRequest(request);
Context context = new StandardContext();
context.setPath("carbon1");
context.addParameter("doAuthentication", String.valueOf(true));
@@ -85,6 +88,22 @@ public class WebappAuthenticationValveTest {
webappAuthenticationValve.invoke(request, null, compositeValve);
}
+ private void getCoyoteRequest(Request request) throws
+ IllegalAccessException,
+ NoSuchFieldException {
+
+ Field headersField = org.apache.coyote.Request.class.getDeclaredField("headers");
+ headersField.setAccessible(true);
+ org.apache.coyote.Request coyoteRequest = new org.apache.coyote.Request();
+
+ MimeHeaders mimeHeaders = new MimeHeaders();
+ MessageBytes bytes = mimeHeaders.addValue("content-type");
+ bytes.setString("test");
+
+ headersField.set(coyoteRequest, mimeHeaders);
+ request.setCoyoteRequest(coyoteRequest);
+ }
+
@Test(description = "This method tests the behaviour of the invoke method of WebAuthenticationValve when "
+ "secured endpoints are invoked.")
public void testInvokeSecuredEndpoints() throws NoSuchFieldException, IllegalAccessException {