Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make non-admin user read-only with a config #432

Merged
merged 2 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.nimbusds.oauth2.sdk.id.ClientID;
import com.nimbusds.oauth2.sdk.id.Issuer;
import io.asgardeo.java.oidc.sdk.config.model.OIDCAgentConfig;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.eclipse.jetty.server.Connector;
Expand Down Expand Up @@ -120,6 +121,9 @@ public class DashboardServer {
private static SSOConfig ssoConfig;
private static Thread shutdownHook;
private static SecretResolver secretResolver = new SecretResolver();
private static boolean makeNonAdminUsersReadOnly;
private static final String TOML_MAKE_NON_ADMIN_USERS_READ_ONLY = "user_access.make_non_admin_users_read_only";
private static final String MAKE_NON_ADMIN_USERS_READ_ONLY = "make_non_admin_users_read_only";

private static final Logger logger = LogManager.getLogger(DashboardServer.class);

Expand Down Expand Up @@ -313,6 +317,15 @@ private void loadConfigurations(Map<String, Object> parsedConfigs) {
properties.put(IS_USER_STORE_FILE_BASED, String.valueOf(isFileBased));
}

String makeNonAdminUsersReadOnlySystemValue = System.getProperty(MAKE_NON_ADMIN_USERS_READ_ONLY);
if (StringUtils.isNotEmpty(makeNonAdminUsersReadOnlySystemValue)) {
makeNonAdminUsersReadOnly = Boolean.parseBoolean(makeNonAdminUsersReadOnlySystemValue);
} else {
makeNonAdminUsersReadOnly = Boolean.parseBoolean(
String.valueOf(parsedConfigs.get(TOML_MAKE_NON_ADMIN_USERS_READ_ONLY)));
}
properties.put(MAKE_NON_ADMIN_USERS_READ_ONLY, String.valueOf(makeNonAdminUsersReadOnly));

System.setProperties(properties);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public class AuthenticationFilter implements ContainerRequestFilter {
private static final String AUTHENTICATION_SCHEME = "Bearer";
private static final List<String> adminOnlyPaths = Arrays.asList("/log-configs",
"/users");
private static final String MAKE_NON_ADMIN_USERS_READ_ONLY = "make_non_admin_users_read_only";

@Context
private HttpServletRequest servletRequest;
Expand All @@ -63,6 +64,8 @@ public void filter(ContainerRequestContext requestContext) {
Map<String, Cookie> cookies = requestContext.getCookies();
String token;
SecurityHandler securityHandler;
Boolean makeNonAdminUsersReadOnly = Boolean.valueOf(System.getProperty(MAKE_NON_ADMIN_USERS_READ_ONLY));
String httpMethod = requestContext.getMethod();

if (isTokenBasedAuthentication(authorizationHeader)) {
token = authorizationHeader.substring(AUTHENTICATION_SCHEME.length()).trim();
Expand All @@ -87,6 +90,11 @@ public void filter(ContainerRequestContext requestContext) {

if (isAdminResource(requestContext) && !securityHandler.isAuthorized(config, token)) {
abortWithUnauthorized(requestContext);
} else if (!"GET".equalsIgnoreCase(httpMethod) && makeNonAdminUsersReadOnly &&
!securityHandler.isAuthorized(config, token)) {
// For non-admin resources, request except GET are blocked
// if the 'makeNonAdminUsersReadOnly' is set to 'true'
abortWithUnauthorized(requestContext);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,33 @@ export default class AuthManager {
static getBasePath() {
return window.location.protocol+'//'+window.location.hostname+(window.location.port ? ':'+window.location.port: '') + "/dashboard/api";
}

/**
* Check whether the user is an admin user.
* @returns {boolean} true if the user is an admin user
*/
static isAdminUser() {
const userName = AuthManager.getUser();
return userName?.scope === "admin";
}

/**
* Check if non-admin users are read-only based on a config.
* @returns {boolean} true if non-admin users are read-only
*/
static isNonAdminUserReadOnly() {
const makeNonAdminUsersReadOnly = window.userAccess.makeNonAdminUsersReadOnly;
return makeNonAdminUsersReadOnly === true;
}

/**
* Check if the current user has edit permissions.
* All the admin users can edit and if the 'isNonAdminUserReadOnly' is false,
* non-admin users also can edit
* @returns {boolean} true if the user has edit permissions
*/
static hasEditPermission() {
return AuthManager.isAdminUser() || !AuthManager.isNonAdminUserReadOnly();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ function SwitchStatusCell(props) {
const { pageId, artifactName, nodeId, status, retrieveData} = props;
var isActive = status;
const globalGroupId = useSelector(state => state.groupId);
const hasEditPermission = AuthManager.hasEditPermission();

const changeState = () => {
isActive = !isActive
Expand All @@ -254,7 +255,7 @@ function SwitchStatusCell(props) {
});
}

return <tr><td><Switch checked={isActive} onChange={changeState} height={16} width={36} /></td></tr>
return <tr><td><Switch checked={isActive} onChange={changeState} height={16} width={36} disabled={!hasEditPermission}/></td></tr>
}

function LogConfigLevelDropDown(props) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ import { TableCell, TableRow } from '@material-ui/core';
import { useSelector } from 'react-redux';
import Switch from "react-switch";
import HTTPClient from '../../../utils/HTTPClient';
import AuthManager from "../../../auth/AuthManager";

export default function TracingRow(props) {
const {pageId, artifactName, nodeId, tracing, retrieveUpdatedArtifact} = props;
var isTracingEnabled = false;
const hasEditPermission = AuthManager.hasEditPermission();

if(tracing === 'enabled') {
isTracingEnabled = true;
Expand Down Expand Up @@ -63,7 +65,7 @@ export default function TracingRow(props) {
<TableCell>Tracing</TableCell>
<TableCell>
<label>
<Switch checked={tracingState} onChange={changeTracingStatus} height={16} width={36} />
<Switch checked={tracingState} onChange={changeTracingStatus} height={16} width={36} disabled={!hasEditPermission} />
</label>
</TableCell>
</TableRow>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,8 @@ window.sso = {
window.userStore = {
type : "{{user_store.type | default('file_based') }}"
};

window.userAccess = {
makeNonAdminUsersReadOnly: {{ user_access.make_non_admin_users_read_only | default(false) }}
};

Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,6 @@ password = "wso2carbon"
#user.name = "admin"
#user.password = "admin"
#user.is_admin = true

[user_access]
make_non_admin_users_read_only = false