Merge branch 'develop' into stable

This commit is contained in:
2025-01-09 16:05:18 -05:00
20 changed files with 123 additions and 83 deletions

View File

@@ -0,0 +1,36 @@
package com.inteligr8.alfresco.asie.model;
import java.io.Serializable;
public class PersistedNode implements Serializable {
private static final long serialVersionUID = 4105196543023419818L;
private final SolrHost node;
private final long persistMillis;
private long expireTimeMillis;
public PersistedNode(SolrHost node, int persistMinutes) {
this.node = node;
this.persistMillis = persistMinutes * 60L * 1000L;
this.reset();
}
public void reset() {
this.expireTimeMillis = System.currentTimeMillis() + this.persistMillis;
}
public boolean isExpired() {
return this.expireTimeMillis < System.currentTimeMillis();
}
public SolrHost getNode() {
return this.node;
}
@Override
public String toString() {
return "node: " + this.node + "; expires in: " + (System.currentTimeMillis() - this.expireTimeMillis) + " ms";
}
}

View File

@@ -1,13 +1,10 @@
package com.inteligr8.alfresco.asie.rest;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
@@ -23,7 +20,7 @@ import com.inteligr8.rs.ClientCxfImpl;
import jakarta.ws.rs.client.ClientRequestContext;
public abstract class AbstractAsieWebScript extends AbstractWebScript implements InitializingBean {
public abstract class AbstractAsieWebScript extends AbstractWebScript {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@@ -42,9 +39,6 @@ public abstract class AbstractAsieWebScript extends AbstractWebScript implements
@Value("${solr.sharedSecret}")
private String solrSharedSecret;
@Value("${inteligr8.asie.allowedAuthorities}")
private String authorizedAuthoritiesStr;
@Value("${inteligr8.asie.basePath}")
private String solrBaseUrl;
@@ -52,28 +46,11 @@ public abstract class AbstractAsieWebScript extends AbstractWebScript implements
@Qualifier(Constants.QUALIFIER_ASIE)
private ObjectMapper objectMapper;
private Set<String> authorizedAuthorities;
@Override
public void afterPropertiesSet() throws Exception {
this.authorizedAuthorities = new HashSet<>();
String[] authorities = this.authorizedAuthoritiesStr.split(",");
for (String authority : authorities) {
authority = StringUtils.trimToNull(authority);
if (authority != null)
this.authorizedAuthorities.add(authority);
}
if (this.authorizedAuthorities.isEmpty())
this.logger.warn("All authenticated users will be authorized to access ASIE web scripts");
super.afterPropertiesSet();
this.solrSharedSecret = StringUtils.trimToNull(this.solrSharedSecret);
}
@Override
protected Set<String> getAuthorities() {
return this.authorizedAuthorities;
}
protected ObjectMapper getObjectMapper() {
return this.objectMapper;

View File

@@ -4,11 +4,19 @@ import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.security.AuthorityService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.extensions.webscripts.Description.RequiredAuthentication;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse;
@@ -16,9 +24,38 @@ import org.springframework.http.HttpStatus;
import net.sf.acegisecurity.GrantedAuthority;
public abstract class AbstractWebScript extends org.springframework.extensions.webscripts.AbstractWebScript {
public abstract class AbstractWebScript extends org.springframework.extensions.webscripts.AbstractWebScript implements InitializingBean {
protected abstract Set<String> getAuthorities();
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Value("${inteligr8.asie.allowedAuthorities}")
private String authorizedAuthoritiesStr;
@Autowired
private AuthorityService authorityService;
private Set<String> authorizedAuthorities;
@Override
public void afterPropertiesSet() throws Exception {
this.authorizedAuthorities = new HashSet<>();
String[] authorities = this.authorizedAuthoritiesStr.split(",");
for (String authority : authorities) {
authority = StringUtils.trimToNull(authority);
if (authority != null)
this.authorizedAuthorities.add(authority);
}
if (this.authorizedAuthorities.isEmpty()) {
this.logger.warn("All authenticated users will be authorized to access web scripts");
} else {
this.logger.debug("Allowing only authorities: {}", this.authorizedAuthorities);
}
}
protected Set<String> getAuthorities() {
return this.authorizedAuthorities;
}
@Override
public final void execute(WebScriptRequest request, WebScriptResponse response) throws IOException {
@@ -38,6 +75,13 @@ public abstract class AbstractWebScript extends org.springframework.extensions.w
return true;
}
Set<String> authorities = this.authorityService.getAuthoritiesForUser(AuthenticationUtil.getFullyAuthenticatedUser());
if (authorities != null) {
if (!Collections.disjoint(this.getAuthorities(), authorities))
return true;
}
this.logger.trace("Not authorized: user '{}'; authorities: {} + {}", AuthenticationUtil.getFullyAuthenticatedUser(), AuthenticationUtil.getFullAuthentication().getAuthorities(), authorities);
return false;
}

View File

@@ -3,7 +3,6 @@ package com.inteligr8.alfresco.asie.rest;
import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.extensions.webscripts.AbstractWebScript;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse;
import org.springframework.http.HttpStatus;
@@ -20,13 +19,13 @@ public class ClearRegistryWebScript extends AbstractWebScript {
@Autowired
private ShardStateService sss;
@Override
public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException {
@Override
public void executeAuthorized(WebScriptRequest request, WebScriptResponse response) throws IOException {
this.sss.clear();
this.sbs.forget();
res.setStatus(HttpStatus.OK.value());
response.setStatus(HttpStatus.OK.value());
}
}

View File

@@ -1,7 +1,5 @@
package com.inteligr8.alfresco.asie.service;
import java.io.Serializable;
import org.alfresco.service.cmr.attributes.AttributeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -11,6 +9,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.inteligr8.alfresco.asie.Constants;
import com.inteligr8.alfresco.asie.model.PersistedNode;
import com.inteligr8.alfresco.asie.model.ShardSet;
import com.inteligr8.alfresco.asie.model.SolrHost;
@@ -31,13 +30,13 @@ public class ShardBackupService implements com.inteligr8.alfresco.asie.spi.Shard
String shardKey = shardSet.getCore() + "-" + shardId;
PersistedNode backupNode = (PersistedNode) this.attributeService.getAttribute(Constants.ATTR_ASIE, ATTR_BACKUP_NODE, shardKey);
this.logger.debug("Found backup node: {}", backupNode);
logger.debug("Found backup node: {}", backupNode);
if (backupNode == null || backupNode.isExpired()) {
backupNode = new PersistedNode(node);
backupNode = new PersistedNode(node, this.persistTimeMinutes);
this.attributeService.setAttribute(backupNode, Constants.ATTR_ASIE, ATTR_BACKUP_NODE, shardKey);
}
return backupNode.getNode();
}
@@ -49,38 +48,5 @@ public class ShardBackupService implements com.inteligr8.alfresco.asie.spi.Shard
String shardKey = shardSet.getCore() + "-" + shardId;
this.attributeService.removeAttribute(Constants.ATTR_ASIE, ATTR_BACKUP_NODE, shardKey);
}
private class PersistedNode implements Serializable {
private static final long serialVersionUID = 4105196543023419818L;
private final SolrHost node;
private long expireTimeMillis;
PersistedNode(SolrHost node) {
this.node = node;
this.reset();
}
void reset() {
this.expireTimeMillis = System.currentTimeMillis() + persistTimeMinutes * 60L * 1000L;
}
boolean isExpired() {
return this.expireTimeMillis < System.currentTimeMillis();
}
SolrHost getNode() {
return this.node;
}
@Override
public String toString() {
return "node: " + this.node + "; expires in: " + (System.currentTimeMillis() - this.expireTimeMillis) + " ms";
}
}
}

View File

@@ -38,6 +38,9 @@
<!-- Security -->
<authentication>none</authentication>
<!-- Transaction -->
<transaction>required</transaction>
<!-- Functionality -->
<cache>
<never>false</never>

View File

@@ -34,6 +34,9 @@
<!-- Security -->
<authentication>none</authentication>
<!-- Transaction -->
<transaction>required</transaction>
<!-- Functionality -->
<cache>
<never>false</never>

View File

@@ -29,7 +29,10 @@
<url>/inteligr8/asie/node/{nodeEndpoint}</url>
<!-- Security -->
<authentication>admin</authentication>
<authentication>user</authentication>
<!-- Transaction -->
<transaction>required</transaction>
<!-- Functionality -->
<cache>

View File

@@ -58,7 +58,7 @@
<format default="json">any</format>
<!-- Security -->
<authentication>admin</authentication>
<authentication>user</authentication>
<!-- Functionality -->
<cache>

View File

@@ -31,7 +31,7 @@
<url>/inteligr8/asie/node/{nodeEndpoint}?coreName={coreName?}&amp;shardRange={shardRange?}&amp;template={template?}&amp;shardCount={shardCount?}&amp;nodeId={nodeId?}&amp;nodeCount={nodeCount?}</url>
<!-- Security -->
<authentication>admin</authentication>
<authentication>user</authentication>
<!-- Functionality -->
<cache>

View File

@@ -32,7 +32,10 @@
<url>/inteligr8/asie/node/{nodeEndpoint}/shard/{shardCore}/{shardId}</url>
<!-- Security -->
<authentication>admin</authentication>
<authentication>user</authentication>
<!-- Transaction -->
<transaction>required</transaction>
<!-- Functionality -->
<cache>

View File

@@ -30,7 +30,7 @@
<url>/inteligr8/asie/node/{nodeEndpoint}/shard/{shardCore}/{shardId}</url>
<!-- Security -->
<authentication>admin</authentication>
<authentication>user</authentication>
<!-- Functionality -->
<cache>

View File

@@ -30,7 +30,10 @@
<url>/inteligr8/asie/node/{nodeEndpoint}/shard/{shardCore}/{shardId}</url>
<!-- Security -->
<authentication>admin</authentication>
<authentication>user</authentication>
<!-- Transaction -->
<transaction>required</transaction>
<!-- Functionality -->
<cache>

View File

@@ -54,7 +54,7 @@
<format default="json">any</format>
<!-- Security -->
<authentication>admin</authentication>
<authentication>user</authentication>
<!-- Functionality -->
<cache>

View File

@@ -61,7 +61,7 @@
<format default="json">any</format>
<!-- Security -->
<authentication>admin</authentication>
<authentication>user</authentication>
<!-- Functionality -->
<cache>

View File

@@ -21,7 +21,10 @@
<url>/inteligr8/asie/nodes</url>
<!-- Security -->
<authentication>admin</authentication>
<authentication>user</authentication>
<!-- Transaction -->
<transaction>required</transaction>
<!-- Functionality -->
<cache>

View File

@@ -47,7 +47,7 @@
<format default="json">any</format>
<!-- Security -->
<authentication>admin</authentication>
<authentication>user</authentication>
<!-- Functionality -->
<cache>

View File

@@ -60,7 +60,7 @@
<format default="json">any</format>
<!-- Security -->
<authentication>admin</authentication>
<authentication>user</authentication>
<!-- Functionality -->
<cache>

View File

@@ -57,7 +57,7 @@
<format default="json">any</format>
<!-- Security -->
<authentication>admin</authentication>
<authentication>user</authentication>
<!-- Functionality -->
<cache>

View File

@@ -2,7 +2,7 @@
# defaulting to 3 days = 60 * 24 * 3 = 4320
inteligr8.asie.backup.persistTimeMinutes=4320
inteligr8.asie.allowedAuthorities=ALFRESCO_ADMINISTRATORS
inteligr8.asie.allowedAuthorities=GROUP_ALFRESCO_ADMINISTRATORS
# same as solr.baseUrl, but that property is private to the Search subsystem
inteligr8.asie.basePath=/solr