mirror of
https://github.com/bmlong137/alfresco-keycloak.git
synced 2025-09-10 14:11:09 +00:00
Enable roles for authority lookup / permission management
This commit is contained in:
@@ -88,6 +88,12 @@
|
||||
<classifier>installable</classifier>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>de.acosix.alfresco.utility</groupId>
|
||||
<artifactId>de.acosix.alfresco.utility.repo</artifactId>
|
||||
<classifier>installable</classifier>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>de.acosix.alfresco.utility</groupId>
|
||||
<artifactId>de.acosix.alfresco.utility.core.share</artifactId>
|
||||
|
@@ -392,6 +392,10 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I
|
||||
|
||||
this.continueFilterChain(context, request, response, chain);
|
||||
}
|
||||
else if (res.isCommitted())
|
||||
{
|
||||
LOGGER.debug("Response has already been committed by skip condition-check - not processing it any further");
|
||||
}
|
||||
else
|
||||
{
|
||||
this.processKeycloakAuthenticationAndActions(context, req, res, chain);
|
||||
@@ -819,34 +823,34 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I
|
||||
|
||||
if (!this.externalAuthEnabled || !this.filterEnabled)
|
||||
{
|
||||
LOGGER.debug("Skipping doFilter as filter and/or external authentication are not enabled");
|
||||
LOGGER.debug("Skipping processKeycloakAuthenticationAndActions as filter and/or external authentication are not enabled");
|
||||
skip = true;
|
||||
}
|
||||
else if (this.keycloakDeployment == null)
|
||||
{
|
||||
LOGGER.debug("Skipping doFilter as Keycloak adapter was not properly initialised");
|
||||
LOGGER.debug("Skipping processKeycloakAuthenticationAndActions as Keycloak adapter was not properly initialised");
|
||||
skip = true;
|
||||
}
|
||||
else if (servletRequestUri.matches(KEYCLOAK_ACTION_URL_PATTERN))
|
||||
{
|
||||
LOGGER.debug("Explicitly not skipping doFilter as Keycloak action URL is being called");
|
||||
LOGGER.debug("Explicitly not skipping processKeycloakAuthenticationAndActions as Keycloak action URL is being called");
|
||||
}
|
||||
else if (req.getParameter("state") != null && req.getParameter("code") != null && this.hasStateCookie(req))
|
||||
{
|
||||
LOGGER.debug(
|
||||
"Explicitly not skipping doFilter as state and code query parameters of OAuth2 redirect as well as state cookie are present");
|
||||
"Explicitly not skipping processKeycloakAuthenticationAndActions as state and code query parameters of OAuth2 redirect as well as state cookie are present");
|
||||
}
|
||||
else if (authHeader != null && authHeader.toLowerCase(Locale.ENGLISH).startsWith("bearer "))
|
||||
{
|
||||
LOGGER.debug("Explicitly not skipping doFilter as Bearer authorization header is present");
|
||||
LOGGER.debug("Explicitly not skipping processKeycloakAuthenticationAndActions as Bearer authorization header is present");
|
||||
}
|
||||
else if (authHeader != null && authHeader.toLowerCase(Locale.ENGLISH).startsWith("basic "))
|
||||
{
|
||||
LOGGER.debug("Explicitly not skipping doFilter as Basic authorization header is present");
|
||||
LOGGER.debug("Explicitly not skipping processKeycloakAuthenticationAndActions as Basic authorization header is present");
|
||||
}
|
||||
else if (authHeader != null)
|
||||
{
|
||||
LOGGER.debug("Skipping doFilter as non-OIDC / non-Basic authorization header is present");
|
||||
LOGGER.debug("Skipping processKeycloakAuthenticationAndActions as non-OIDC / non-Basic authorization header is present");
|
||||
skip = true;
|
||||
}
|
||||
else if (currentSession != null && AuthenticationUtil.isAuthenticated(req))
|
||||
@@ -858,7 +862,11 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.debug("Skipping doFilter as non-Keycloak-authenticated session is already established");
|
||||
// TODO Validate via custom /touch to check if session is still valid
|
||||
// custom => handle potential 302 instead of 401 response from Keycloak-enabled backend
|
||||
// custom => deal with redirect host being unknown (similar to our auth-server-url vs. directAuthHost case)
|
||||
LOGGER.debug(
|
||||
"Skipping processKeycloakAuthenticationAndActions as non-Keycloak-authenticated session is already established");
|
||||
skip = true;
|
||||
}
|
||||
}
|
||||
@@ -868,26 +876,26 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I
|
||||
final String noauth = proxyMatcher.group(2);
|
||||
if (noauth != null && !noauth.trim().isEmpty())
|
||||
{
|
||||
LOGGER.debug("Skipping doFilter as proxy servlet to noauth endpoint {} is being called");
|
||||
LOGGER.debug("Skipping processKeycloakAuthenticationAndActions as proxy servlet to noauth endpoint {} is being called");
|
||||
skip = true;
|
||||
}
|
||||
else if (!endpoint.equals(this.primaryEndpoint)
|
||||
&& (this.secondaryEndpoints == null || !this.secondaryEndpoints.contains(endpoint)))
|
||||
{
|
||||
LOGGER.debug(
|
||||
"Skipping doFilter on proxy servlet call as endpoint {} has not been configured as a primary / secondary endpoint to handle");
|
||||
"Skipping processKeycloakAuthenticationAndActions on proxy servlet call as endpoint {} has not been configured as a primary / secondary endpoint to handle");
|
||||
skip = true;
|
||||
}
|
||||
}
|
||||
else if (PAGE_SERVLET_PATH.equals(servletPath) && (LOGIN_PATH_INFORMATION.equals(pathInfo)
|
||||
|| (pathInfo == null && LOGIN_PAGE_TYPE_PARAMETER_VALUE.equals(req.getParameter(PAGE_TYPE_PARAMETER_NAME)))))
|
||||
{
|
||||
LOGGER.debug("Skipping doFilter as login page was explicitly requested");
|
||||
LOGGER.debug("Skipping processKeycloakAuthenticationAndActions as login page was explicitly requested");
|
||||
skip = true;
|
||||
}
|
||||
else if (this.isNoAuthPage(req))
|
||||
{
|
||||
LOGGER.debug("Skipping doFilter as requested page does not require authentication");
|
||||
LOGGER.debug("Skipping processKeycloakAuthenticationAndActions as requested page does not require authentication");
|
||||
skip = true;
|
||||
}
|
||||
|
||||
@@ -928,7 +936,7 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I
|
||||
boolean skip = false;
|
||||
if (currentSession != null)
|
||||
{
|
||||
LOGGER.debug("Skipping doFilter as Keycloak-authentication session is still valid");
|
||||
LOGGER.debug("Skipping processKeycloakAuthenticationAndActions as Keycloak-authentication session is still valid");
|
||||
skip = true;
|
||||
|
||||
if (keycloakAccount instanceof OidcKeycloakAccount)
|
||||
|
@@ -0,0 +1,3 @@
|
||||
<@markup id="keycloak-js" target="js" action="after">
|
||||
<@script src="${url.context}/res/acosix/keycloak/components/manage-permissions/manage-permissions.js" group="manage-permissions"/>
|
||||
</@>
|
@@ -0,0 +1,45 @@
|
||||
function main()
|
||||
{
|
||||
var requestedAuthorityType, filter, maxResults, url, response, responseObj, authorities, idx;
|
||||
|
||||
requestedAuthorityType = args.authorityType ? String(args.authorityType).toLowerCase() : 'all';
|
||||
filter = args.filter ? String(args.filter) : null;
|
||||
maxResults = args.maxResults ? parseInt(String(args.maxResults)) : 0;
|
||||
|
||||
if (requestedAuthorityType === 'all')
|
||||
{
|
||||
url = '/acosix/api/keycloak/roles';
|
||||
if (maxResults > 0)
|
||||
{
|
||||
url += '?maxItems=' + maxResults;
|
||||
}
|
||||
if (filter)
|
||||
{
|
||||
url += url.indexOf('?') === -1 ? '?' : '&';
|
||||
url += 'shortNameFilter=' + encodeURIComponent(filter);
|
||||
}
|
||||
response = remote.call(url);
|
||||
if (response.status.code === 200)
|
||||
{
|
||||
responseObj = JSON.parse(response.text);
|
||||
authorities = model.authorities;
|
||||
|
||||
for (idx = 0; idx < responseObj.data.length; idx++)
|
||||
{
|
||||
// UI likely cannot handle authorityType ROLE, which would be semantically correct
|
||||
authorities.push({
|
||||
authorityType : 'GROUP',
|
||||
shortName : responseObj.data[idx].shortName,
|
||||
fullName : responseObj.data[idx].fullName,
|
||||
displayName : responseObj.data[idx].displayName,
|
||||
description : responseObj.data[idx].fullName,
|
||||
metadata : {}
|
||||
});
|
||||
}
|
||||
|
||||
model.authorities = authorities;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
@@ -0,0 +1,35 @@
|
||||
(function()
|
||||
{
|
||||
var Dom = YAHOO.util.Dom;
|
||||
|
||||
if (Alfresco.component.ManagePermissions)
|
||||
{
|
||||
Alfresco.component.ManagePermissions.prototype.fnRenderCellAuthorityIcon = function Acosix_Keycloak_ManagePermissions_fnRenderCellAuthorityIcon()
|
||||
{
|
||||
return function Acosix_Keycloak_ManagePermissions_renderCellAuthorityIcon(elCell, oRecord, oColumn)
|
||||
{
|
||||
var authority, isGroupLike, iconUrl;
|
||||
|
||||
Dom.setStyle(elCell, 'width', oColumn.width + 'px');
|
||||
Dom.setStyle(elCell.parentNode, 'width', oColumn.width + 'px');
|
||||
|
||||
authority = oRecord.getData('authority');
|
||||
// main modification - treat ROLE just like a group, because any number of users can belong to a role
|
||||
isGroupLike = /^(GROUP|ROLE)_.*/.test(authority.name);
|
||||
// end main modification
|
||||
iconUrl = Alfresco.constants.URL_RESCONTEXT + 'components/images/' + (isGroupLike ? 'group' : 'no-user-photo') + '-64.png';
|
||||
|
||||
if (authority.avatar && authority.avatar.length !== 0)
|
||||
{
|
||||
iconUrl = Alfresco.constants.PROXY_URI + authority.avatar + '?c=queue&ph=true';
|
||||
}
|
||||
else if (authority.iconUrl)
|
||||
{
|
||||
// As passed-back from the Authority Finder component
|
||||
iconUrl = authority.iconUrl;
|
||||
}
|
||||
elCell.innerHTML = '<img class="icon32" src="' + iconUrl + '" alt="icon" />';
|
||||
};
|
||||
};
|
||||
}
|
||||
}());
|
@@ -21,18 +21,10 @@
|
||||
<connector>
|
||||
<id>alfrescoCookie</id>
|
||||
<name>Alfresco Connector</name>
|
||||
<description>Connects to an Alfresco instance using cookie-based authentication</description>
|
||||
<description>Connects to an Alfresco instance using cookie-based authentication and awareness of OIDC bearer tokens</description>
|
||||
<class>de.acosix.alfresco.keycloak.share.remote.BearerTokenAwareSlingshotAlfrescoConnector</class>
|
||||
</connector>
|
||||
|
||||
<connector>
|
||||
<id>alfrescoHeader</id>
|
||||
<name>Alfresco Connector</name>
|
||||
<description>Connects to an Alfresco instance using header and cookie-based authentication</description>
|
||||
<class>de.acosix.alfresco.keycloak.share.remote.BearerTokenAwareSlingshotAlfrescoConnector</class>
|
||||
<userHeader>SsoUserHeader</userHeader>
|
||||
</connector>
|
||||
|
||||
<endpoint>
|
||||
<id>alfresco</id>
|
||||
<name>Alfresco - user access</name>
|
||||
@@ -47,7 +39,7 @@
|
||||
<id>alfresco-feed</id>
|
||||
<name>Alfresco Feed</name>
|
||||
<description>Alfresco Feed - supports basic HTTP authentication via the EndPointProxyServlet</description>
|
||||
<connector-id>alfrescoHeader</connector-id>
|
||||
<connector-id>alfrescoCookie</connector-id>
|
||||
<endpoint-url>http://repository:8080/alfresco/wcs</endpoint-url>
|
||||
<basic-auth>true</basic-auth>
|
||||
<identity>user</identity>
|
||||
@@ -58,10 +50,8 @@
|
||||
<id>alfresco-api</id>
|
||||
<parent-id>alfresco</parent-id>
|
||||
<name>Alfresco Public API - user access</name>
|
||||
<description>Access to Alfresco Repository Public API that require user authentication.
|
||||
This makes use of the authentication that is provided by parent 'alfresco' endpoint.
|
||||
</description>
|
||||
<connector-id>alfrescoHeader</connector-id>
|
||||
<description>Access to Alfresco Repository Public API that require user authentication. This makes use of the authentication that is provided by parent 'alfresco' endpoint. </description>
|
||||
<connector-id>alfrescoCookie</connector-id>
|
||||
<endpoint-url>http://repository:8080/alfresco/api</endpoint-url>
|
||||
<identity>user</identity>
|
||||
<external-auth>true</external-auth>
|
||||
|
@@ -70,6 +70,8 @@
|
||||
<include>de.acosix.alfresco.utility:de.acosix.alfresco.utility.core.repo.quartz2:*</include>
|
||||
<include>${project.groupId}:de.acosix.alfresco.keycloak.repo.deps:*</include>
|
||||
<include>de.acosix.alfresco.utility:de.acosix.alfresco.utility.core.repo:jar:installable:*</include>
|
||||
<!-- full acosix-utility repo module required for extension to repository-tier permissions.post.json.js to take effect -->
|
||||
<include>de.acosix.alfresco.utility:de.acosix.alfresco.utility.repo:jar:installable:*</include>
|
||||
<include>${project.groupId}:de.acosix.alfresco.keycloak.repo:jar:installable:*</include>
|
||||
</includes>
|
||||
<scope>test</scope>
|
||||
|
Reference in New Issue
Block a user