Skip to content
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
17 changes: 16 additions & 1 deletion api/src/org/labkey/api/action/PermissionCheckableAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package org.labkey.api.action;

import jakarta.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable;
import org.labkey.api.data.Container;
import org.labkey.api.module.IgnoresForbiddenProjectCheck;
Expand All @@ -39,6 +40,7 @@
import org.labkey.api.security.roles.RoleManager;
import org.labkey.api.util.ConfigurationException;
import org.labkey.api.util.HttpUtil;
import org.labkey.api.util.logging.LogHelper;
import org.labkey.api.view.BadRequestException;
import org.labkey.api.view.NotFoundException;
import org.labkey.api.view.RedirectException;
Expand All @@ -55,6 +57,7 @@

public abstract class PermissionCheckableAction implements Controller, PermissionCheckable, HasViewContext
{
private static final Logger LOG = LogHelper.getLogger(PermissionCheckableAction.class, "Permission checks for actions");
private static final HttpUtil.Method[] arrayGetPost = new HttpUtil.Method[] {Method.GET, Method.POST};
private ViewContext _context = null;
UnauthorizedException.Type _unauthorizedType = UnauthorizedException.Type.redirectToLogin;
Expand Down Expand Up @@ -148,6 +151,8 @@ private void _checkActionPermissions(Set<Role> contextualRoles) throws Unauthori
Container c = context.getContainer();
User user = context.getUser();
Class<? extends Controller> actionClass = getClass();
if (LOG.isDebugEnabled())
LOG.debug(actionClass.getName() + ": checking permissions for user " + (user == null ? "<null>" : user.getName() + " (impersonated=" + user.isImpersonated() + ")"));

if (!actionClass.isAnnotationPresent(IgnoresForbiddenProjectCheck.class))
c.throwIfForbiddenProject(user);
Expand All @@ -159,18 +164,22 @@ private void _checkActionPermissions(Set<Role> contextualRoles) throws Unauthori
methodsAllowed = methodsAllowedAnnotation.value();
if (Arrays.stream(methodsAllowed).noneMatch(s -> s.equals(method)))
{
throw new BadRequestException("Method Not Allowed: " + method, null, HttpServletResponse.SC_METHOD_NOT_ALLOWED);
String msg = "Method Not Allowed: " + method;
LOG.debug(msg);
throw new BadRequestException(msg, null, HttpServletResponse.SC_METHOD_NOT_ALLOWED);
}

boolean requiresSiteAdmin = actionClass.isAnnotationPresent(RequiresSiteAdmin.class);
if (requiresSiteAdmin && !user.hasSiteAdminPermission())
{
LOG.debug(actionClass.getName() + ": action requires site admin permissions");
throw new UnauthorizedException();
}

boolean requiresLogin = actionClass.isAnnotationPresent(RequiresLogin.class);
if (requiresLogin && user.isGuest())
{
LOG.debug(actionClass.getName() + ": action requires login (non-guest)");
throw new UnauthorizedException();
}

Expand Down Expand Up @@ -214,7 +223,10 @@ private void _checkActionPermissions(Set<Role> contextualRoles) throws Unauthori
// Must have all permissions in permissionsRequired
if (!SecurityManager.hasAllPermissions(this.getClass().getName()+"_checkActionPermissions",
c, user, permissionsRequired, contextualRoles))
{
LOG.debug(actionClass.getName() + ": action requires all permissions: " + permissionsRequired);
throw new UnauthorizedException();
}

CSRF.Method csrfCheck = actionClass.isAnnotationPresent(CSRF.class) ? actionClass.getAnnotation(CSRF.class).value() : CSRF.Method.POST;
csrfCheck.validate(context);
Expand All @@ -228,7 +240,10 @@ private void _checkActionPermissions(Set<Role> contextualRoles) throws Unauthori
Collections.addAll(permissionsAnyOf, requiresAnyOf.value());
if (!SecurityManager.hasAnyPermissions(this.getClass().getName() + "_checkActionPermissions",
c, user, permissionsAnyOf, contextualRoles))
{
LOG.debug(actionClass.getName() + ": action requires any permissions: " + permissionsAnyOf);
throw new UnauthorizedException();
}
}

boolean requiresNoPermission = actionClass.isAnnotationPresent(RequiresNoPermission.class);
Expand Down
13 changes: 11 additions & 2 deletions api/src/org/labkey/api/data/Container.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.labkey.api.query.QueryService;
import org.labkey.api.security.HasPermission;
import org.labkey.api.security.SecurableResource;
import org.labkey.api.security.SecurityLogger;
import org.labkey.api.security.SecurityManager;
import org.labkey.api.security.SecurityPolicy;
import org.labkey.api.security.SecurityPolicyManager;
Expand Down Expand Up @@ -550,7 +551,11 @@ private boolean handleForbiddenProject(User user, Set<Role> contextualRoles, boo
if (null != impersonationProject && !impersonationProject.equals(currentProject))
{
if (shouldThrow)
throw new ForbiddenProjectException("You are not allowed to access this folder while impersonating within a different project.");
{
String msg = "You are not allowed to access this folder while impersonating within a different project.";
SecurityLogger.log(msg, user, null, null);
throw new ForbiddenProjectException(msg);
}

return true;
}
Expand All @@ -563,7 +568,11 @@ private boolean handleForbiddenProject(User user, Set<Role> contextualRoles, boo
if (lockState.isLocked() && ContainerManager.LOCKED_PROJECT_HANDLER.isForbidden(currentProject, user, contextualRoles, lockState))
{
if (shouldThrow)
throw new ForbiddenProjectException("You are not allowed to access this folder; it is " + lockState.getDescription() + ".");
{
String msg = "You are not allowed to access this folder; it is " + lockState.getDescription() + ".";
SecurityLogger.log(msg, user, null, null);
throw new ForbiddenProjectException(msg);
}

return true;
}
Expand Down
2 changes: 1 addition & 1 deletion api/src/org/labkey/api/data/URLDisplayColumn.java
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ public Renderable createThumbnailImage()
String thumbnailUrl = _fileIconUrl != null ? ensureAbsoluteUrl(_ctx, _fileIconUrl) : ensureAbsoluteUrl(_ctx, _url);

return IMG(at(
style, "display:block; vertical-align:middle;" + (renderSize ? (_thumbnailWidth != null ? " width:" + _thumbnailWidth : " max-width:32px" + "; ") + (_thumbnailHeight != null ? " height:" + _thumbnailHeight : " height:auto" + ";") : ""),
style, "display:block; vertical-align:middle;" + (renderSize ? (_thumbnailWidth != null ? " width:" + _thumbnailWidth : " max-width:32px") + "; " + (_thumbnailHeight != null ? " height:" + _thumbnailHeight : " height:auto") + ";" : ""),
src, thumbnailUrl, title, _displayName
));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,22 @@
/*
* Copyright (c) 2009-2014 LabKey Corporation
*
* Licensed 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.labkey.api.exp.list;

/*
* User: adam
* Date: Dec 23, 2009
* Time: 3:05:51 PM
*/
public interface ListImportProgress
{
void setTotalRows(int rows);
void setCurrentRow(int currentRow);
}
/*
* Copyright (c) 2009-2014 LabKey Corporation
*
* Licensed 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.labkey.api.dataiterator;

public interface ImportProgress
{
void setTotalRows(int rows);
void setCurrentRow(int currentRow);
}
5 changes: 2 additions & 3 deletions api/src/org/labkey/api/dataiterator/Pump.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.labkey.api.exp.list.ListImportProgress;
import org.labkey.api.query.BatchValidationException;

import java.io.IOException;
Expand All @@ -34,7 +33,7 @@ public class Pump implements Runnable
final BatchValidationException _errors;
int _errorLimit = Integer.MAX_VALUE;
long _rowCount = 0;
ListImportProgress _progress = null;
ImportProgress _progress = null;

public Pump(DataIterator it, DataIteratorContext context)
{
Expand All @@ -50,7 +49,7 @@ public Pump(DataIteratorBuilder builder, DataIteratorContext context)
_errors = context.getErrors();
}

public void setProgress(ListImportProgress progress)
public void setProgress(ImportProgress progress)
{
_progress = progress;
}
Expand Down
5 changes: 3 additions & 2 deletions api/src/org/labkey/api/exp/list/ListDefinition.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.labkey.api.data.ContainerFilter;
import org.labkey.api.data.LookupResolutionType;
import org.labkey.api.data.TableInfo;
import org.labkey.api.dataiterator.ImportProgress;
import org.labkey.api.exp.DomainNotFoundException;
import org.labkey.api.exp.PropertyType;
import org.labkey.api.exp.property.Domain;
Expand Down Expand Up @@ -269,8 +270,8 @@ public static BodySetting getForValue(int value)
ListItem getListItemForEntityId(String entityId, User user);

int insertListItems(User user, Container container, List<ListItem> listItems) throws IOException;
int insertListItems(User user, Container container, DataLoader loader, @NotNull BatchValidationException errors, @Nullable VirtualFile attachmentDir, @Nullable ListImportProgress progress, boolean supportAutoIncrementKey, LookupResolutionType lookupResolutionType) throws IOException;
int importListItems(User user, Container container, DataLoader loader, @NotNull BatchValidationException errors, @Nullable VirtualFile attachmentDir, @Nullable ListImportProgress progress, boolean supportAutoIncrementKey, LookupResolutionType lookupResolutionType, QueryUpdateService.InsertOption insertOption) throws IOException;
int insertListItems(User user, Container container, DataLoader loader, @NotNull BatchValidationException errors, @Nullable VirtualFile attachmentDir, @Nullable ImportProgress progress, boolean supportAutoIncrementKey, LookupResolutionType lookupResolutionType) throws IOException;
int importListItems(User user, Container container, DataLoader loader, @NotNull BatchValidationException errors, @Nullable VirtualFile attachmentDir, @Nullable ImportProgress progress, boolean supportAutoIncrementKey, LookupResolutionType lookupResolutionType, QueryUpdateService.InsertOption insertOption) throws IOException;

@Nullable TableInfo getTable(User user);
@Nullable TableInfo getTable(User user, Container c);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
import org.labkey.api.data.DbScope;
import org.labkey.api.data.TableInfo;
import org.labkey.api.data.TableSelector;
import org.labkey.api.util.GUID;
import org.labkey.api.util.Pair;

import java.io.PrintWriter;
import java.util.Set;
import java.util.function.Predicate;

Expand All @@ -21,5 +24,8 @@ default void beforeMigration(){}
Predicate<String> getColumnNameFilter();
@Nullable TableSelector getTableSelector(DbSchemaType schemaType, TableInfo sourceTable, TableInfo targetTable, Set<String> selectColumnNames, MigrationSchemaHandler schemaHandler, @Nullable MigrationTableHandler tableHandler);
default void copyAttachments(DbSchema sourceSchema, DbSchema targetSchema, MigrationSchemaHandler schemaHandler){}
default void afterMigration(){}
default @Nullable Pair<FilePathWriter, Set<GUID>> initializeFilePathWriter()
{
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -306,15 +306,15 @@ public static void afterMigration() throws InterruptedException
if (unseen.isEmpty())
LOG.info("All AttachmentTypes have been seen");
else
throw new ConfigurationException("These AttachmentTypes have not been seen: " + unseen.stream().map(type -> type.getClass().getSimpleName()).collect(Collectors.joining(", ")));
LOG.error("These AttachmentTypes have not been seen: {}", unseen.stream().map(type -> type.getClass().getSimpleName()).collect(Collectors.joining(", ")));

// Shut down the attachment JobRunner
LOG.info("Waiting for attachments background transfer to complete");
ATTACHMENT_JOB_RUNNER.shutdown();
if (ATTACHMENT_JOB_RUNNER.awaitTermination(1, TimeUnit.HOURS))
if (ATTACHMENT_JOB_RUNNER.awaitTermination(2, TimeUnit.HOURS))
LOG.info("Attachments background transfer is complete");
else
LOG.error("Attachments background transfer did not complete after one hour! Giving up.");
LOG.error("Attachments background transfer did not complete after two hours! Giving up.");
}

@Override
Expand All @@ -332,4 +332,9 @@ public void afterSchema(DatabaseMigrationConfiguration configuration, DbSchema s
public void afterMigration(DatabaseMigrationConfiguration configuration)
{
}

@Override
public void writeFilePaths(FilePathWriter writer, Set<GUID> guids)
{
}
}
42 changes: 42 additions & 0 deletions api/src/org/labkey/api/migration/FilePathWriter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.labkey.api.migration;

import org.labkey.api.data.ContainerManager;
import org.labkey.api.files.FileContentService;

import java.io.Closeable;
import java.io.File;
import java.io.PrintWriter;
import java.nio.file.Path;

public class FilePathWriter implements Closeable
{
private final PrintWriter _out;
private final Path _rootPath;

public FilePathWriter(PrintWriter out)
{
_out = out;
_rootPath = FileContentService.get().getFileRoot(ContainerManager.getRoot()).toPath();
}

public void write(File file)
{
_out.println(_rootPath.relativize(file.toPath()).normalize());
}

public void println(String s)
{
_out.println(s);
}

public void println()
{
_out.println();
}

@Override
public void close()
{
_out.close();
}
}
3 changes: 3 additions & 0 deletions api/src/org/labkey/api/migration/MigrationSchemaHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.labkey.api.query.FieldKey;
import org.labkey.api.util.GUID;

import java.io.PrintWriter;
import java.util.Collection;
import java.util.List;
import java.util.Set;
Expand Down Expand Up @@ -57,4 +58,6 @@ public interface MigrationSchemaHandler
@NotNull Collection<AttachmentParentType> getAttachmentTypes();

void afterMigration(DatabaseMigrationConfiguration configuration);

void writeFilePaths(FilePathWriter writer, Set<GUID> guids);
}
3 changes: 0 additions & 3 deletions api/src/org/labkey/api/module/ModuleLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -678,9 +678,6 @@ private void doInit(Execution execution) throws ServletException
_log.info("Server installation GUID: {}, server session GUID: {}", AppProps.getInstance().getServerGUID(), AppProps.getInstance().getServerSessionGUID());
_log.info("Deploying to context path {}", AppProps.getInstance().getContextPath());

// Temporary logging to help track down issues we're having with upgrading XMLBeans from v5.2.0. TODO: Remove after upgrade
_log.info("XMLBeans version: {}", XmlBeans.getVersion());

synchronized (_modulesLock)
{
checkForRenamedModules();
Expand Down
1 change: 1 addition & 0 deletions api/src/org/labkey/api/premium/AntiVirusService.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public interface AntiVirusService
{
// NOTE purposefully this is not the same as the standard test file: ...EICAR-STANDARD-ANTIVIRUS-TEST-FILE...
String TEST_VIRUS_CONTENT="X5O!P%@AP[4\\PZX54(P^)7CC)7}$LABKEY-ANTIVIRUS-TEST-FILE!$H+H*";
String MALICIOUS_FILE_ERROR_MESSAGE = "For security reasons, we did not upload this file. Please contact your internal IT or Information Security department for assistance in dealing with this potentially harmful file.";

static @Nullable AntiVirusService get()
{
Expand Down
2 changes: 1 addition & 1 deletion core/src/org/labkey/core/webdav/DavController.java
Original file line number Diff line number Diff line change
Expand Up @@ -3002,7 +3002,7 @@ public void closeInputStream() throws IOException
if (result.result == AntiVirusService.Result.CONFIGURATION_ERROR)
throw new ConfigurationException(result.message);
else
throw new DavException(WebdavStatus.SC_BAD_REQUEST, result.message);
throw new DavException(WebdavStatus.SC_BAD_REQUEST, result.message + ". " + AntiVirusService.MALICIOUS_FILE_ERROR_MESSAGE);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.labkey.api.migration.DatabaseMigrationService.DataFilter;
import org.labkey.api.migration.DefaultMigrationSchemaHandler;
import org.labkey.api.migration.ExperimentDeleteService;
import org.labkey.api.migration.FilePathWriter;
import org.labkey.api.query.FieldKey;
import org.labkey.api.util.GUID;
import org.labkey.api.util.StringUtilsLabKey;
Expand Down Expand Up @@ -95,8 +96,8 @@ public void afterTable(TableInfo sourceTable, TableInfo targetTable, SimpleFilte

// Select all ObjectIds associated with the not-copied rows from the source database
SQLFragment objectIdSql = new SQLFragment("SELECT ObjectId FROM exp.Data d INNER JOIN ")
.appendIdentifier(sourceTable.getSelectName())
.append(" dc ON d.LSID = dc.LSID");
.appendIdentifier(sourceTable.getSelectName())
.append(" dc ON d.LSID = dc.LSID");

// Don't create an empty IN clause; need to work around issue where "NOT xxx IN (NULL)" evaluates to NULL.
if (!copiedLsids.isEmpty())
Expand Down Expand Up @@ -134,7 +135,7 @@ public void afterTable(TableInfo sourceTable, TableInfo targetTable, SimpleFilte
}
})
.forEach(SEQUENCE_IDS::add);
LOG.info("{} added to the SequenceIdentity set",
LOG.info(" {} added to the SequenceIdentity set",
StringUtilsLabKey.pluralize(SEQUENCE_IDS.size() - startSize, "unique SequenceId was", "unique SequenceIds were"));
}
}
Expand Down Expand Up @@ -202,4 +203,11 @@ public FilterClause getTableFilterClause(TableInfo sourceTable, Set<GUID> contai
{
return List.of(ExpDataClassType.get());
}

@Override
public void writeFilePaths(FilePathWriter writer, Set<GUID> guids)
{
// TODO: Enumerate FileLink fields in data classes in the filtered containers (guids) and write out those file
// paths. Current client has none.
}
}
Loading