All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.almworks.jira.structure.api.StructureAuth Maven / Gradle / Ivy

There is a newer version: 17.25.3
Show newest version
package com.almworks.jira.structure.api;

import com.almworks.jira.structure.api.view.StructureView;
import com.almworks.jira.structure.util.CallableE;
import com.atlassian.crowd.embedded.api.User;
import com.atlassian.fugue.Option;
import com.atlassian.fugue.Pair;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.security.JiraAuthenticationContext;
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.jira.user.ApplicationUsers;
import com.atlassian.jira.util.log.Log4jKit;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.atomic.AtomicBoolean;

import static com.atlassian.fugue.Option.option;
import static com.atlassian.fugue.Pair.pair;

/**
 * This is a helper class manages the current authentication context assumed when accessing, managing
 * and updating Structure entities such as {@link Structure} or {@link StructureView}.
 *
 * 

The context is local to the current thread. * *

By default, the context equals to {@link JiraAuthenticationContext JIRA's authentication context}. * It is possible to specify another user or disable security checks. * */ public class StructureAuth { private static final Logger log = LoggerFactory.getLogger(StructureAuth.class); /** * Not using custom class to avoid leaking our classes through ThreadLocal. * Second component is "override security" * */ private static final ThreadLocal, Boolean>> sudoContext = new ThreadLocal<>(); private static final AtomicBoolean reportedNoAuthContext = new AtomicBoolean(); /** * Returns the current user. If the user is not authenticated, i.e. the context is anonymous, * returns {@code null}. "Override security" settings does not influence this method. * */ @Nullable public static ApplicationUser getUser() { Pair, Boolean> context = sudoContext.get(); return context == null ? getJiraUser() : context.left().getOrNull(); } @Nullable @Deprecated public static User getDirectoryUser() { ApplicationUser user = getUser(); return user == null ? null : user.getDirectoryUser(); } @Nullable public static String getUserKey() { return ApplicationUsers.getKeyFor(getUser()); } @Nullable private static ApplicationUser getJiraUser() { JiraAuthenticationContext jiraContext = ComponentAccessor.getJiraAuthenticationContext(); if (jiraContext == null) { if (reportedNoAuthContext.compareAndSet(false, true)) { log.error("JIRA's ComponentAccessor does not provide authentication context. " + "Structure will behave as if everything is executed under anonymous user."); } return null; } return jiraContext.getUser(); } /** * Returns {@code true} if permission checks shouldn't be carried out in this context. * */ public static boolean isSecurityOverridden() { Pair, Boolean> context = sudoContext.get(); return context != null && context.right(); } /** * Execute actions with Structure under a different authentication context - as another user, * and/or with all security checks disabled. * If you only need to override security while keeping user context intact, you can use * {@link #sudo(CallableE) a shorthand override} * * @param user the user, can be {@code null} to represent anonymous * @param overrideSecurity if true, user access level will not be checked for {@code f} * @param f the code to execute, this method will return the computed value. * Can throw {@link E}, it will be propagated. * */ public static R sudo(@Nullable ApplicationUser user, boolean overrideSecurity, CallableE f) throws E { Pair, Boolean> oldContext = sudoContext.get(); sudoContext.set(pair(option(user), overrideSecurity)); JiraAuthenticationContext jiraContext = ComponentAccessor.getJiraAuthenticationContext(); ApplicationUser oldUser = jiraContext.getUser(); jiraContext.setLoggedInUser(user); Log4jKit.putUserToMDC((user == null ? "anonymous" : user.getUsername()) + "<-" + (oldUser == null ? "anonymous" : oldUser.getName())); try { return f.call(); } finally { if (oldContext != null) { sudoContext.set(oldContext); } else { sudoContext.remove(); } jiraContext.setLoggedInUser(oldUser); } } /** * Execute actions with Structure under the current JIRA user with all security checks disabled. * @param f the code to execute, this method will return the computed value. * Can throw {@link E}, it will be propagated. * */ public static R sudo(CallableE f) throws E { return sudo(getUser(), true, f); } public static AuthContext currentContext() { Pair, Boolean> context = sudoContext.get(); return context == null ? new AuthContext.Custom(getJiraUser(), false) : new AuthContext.Custom(context.left().getOrNull(), context.right()); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy