Skip to content
Open
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 @@ -62,7 +62,6 @@ default Stream<IAuthorizationAction> getActions( @Nullable String actionNamespac
.filter( action -> action.getName().startsWith( actionNamespacePrefix ) );
}

// TODO: tests
/**
* Gets an authorization action given its name.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package org.pentaho.platform.api.engine.security.authorization;

import edu.umd.cs.findbugs.annotations.NonNull;
import org.pentaho.platform.api.engine.security.authorization.impl.DefaultAuthorizationOptions;

/**
* The {@code IAuthorizationOptions} interface encapsulates options that control the authorization evaluation process.
Expand All @@ -34,39 +35,7 @@ public interface IAuthorizationOptions {
* @return An instance of {@link IAuthorizationOptions}.
*/
static IAuthorizationOptions getDefault() {
return new IAuthorizationOptions() {
@NonNull
@Override
public AuthorizationDecisionReportingMode getDecisionReportingMode() {
return AuthorizationDecisionReportingMode.SETTLED;
}

@Override
public boolean equals( Object obj ) {
if ( this == obj ) {
return true;
}

if ( !( obj instanceof IAuthorizationOptions ) ) {
return false;
}

IAuthorizationOptions other = (IAuthorizationOptions) obj;
return getDecisionReportingMode() == other.getDecisionReportingMode();
}

@Override
public int hashCode() {
return getDecisionReportingMode().hashCode();
}

@Override
public String toString() {
return String.format(
"IAuthorizationOptions{decisionReportingMode=%s}",
getDecisionReportingMode() );
}
};
return DefaultAuthorizationOptions.INSTANCE;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*! ******************************************************************************
*
* Pentaho
*
* Copyright (C) 2024 by Hitachi Vantara, LLC : http://www.pentaho.com
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file.
*
* Change Date: 2029-07-20
******************************************************************************/

package org.pentaho.platform.api.engine.security.authorization.caching;

import edu.umd.cs.findbugs.annotations.NonNull;
import org.pentaho.platform.api.engine.security.authorization.IAuthorizationOptions;
import org.pentaho.platform.api.engine.security.authorization.IAuthorizationRequest;
import org.pentaho.platform.api.engine.security.authorization.decisions.IAuthorizationDecision;

import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;

/**
* The {@code IAuthorizationDecisionCache} interface represents a cache for authorization decisions,
* and which follows the "loading cache" pattern.
*/
public interface IAuthorizationDecisionCache {
/**
* Gets a cached authorization decision for a specific authorization request and options, if available.
*
* @param request The authorization request.
* @param options The authorization options.
* @return An optional with the cached decision, if found; an empty optional, if not found.
*/
@NonNull
Optional<IAuthorizationDecision> get( @NonNull IAuthorizationRequest request,
@NonNull IAuthorizationOptions options );

/**
* Gets a cached authorization decision for a specific authorization request and options,
* loading it from the given loader function and storing it in the cache, if not available.
*
* @param request The authorization request.
* @param options The authorization options.
* @param loader A function that computes the authorization decision if it is not found in the cache.
* @return The authorization decision.
*/
@NonNull
IAuthorizationDecision get( @NonNull IAuthorizationRequest request,
@NonNull IAuthorizationOptions options,
@NonNull Function<IAuthorizationDecisionCacheKey, IAuthorizationDecision> loader );

/**
* Caches an authorization decision for a specific authorization request and options.
* <p>
* This operation is a no-op if the cache is disabled.
*
* @param request The authorization request.
* @param options The authorization options.
* @param decision The authorization decision to cache.
*/
void put( @NonNull IAuthorizationRequest request,
@NonNull IAuthorizationOptions options,
@NonNull IAuthorizationDecision decision );

/**
* Clears the cached authorization decision for a specific authorization request and options, if any.
*
* @param request The authorization request.
* @param options The authorization options.
*/
void invalidate( @NonNull IAuthorizationRequest request, @NonNull IAuthorizationOptions options );

/**
* Clears all cached authorization decisions for requests and options that match the given predicate.
*
* @param predicate A predicate that matches authorization requests and options to clear from the cache.
*/
void invalidateAll( @NonNull Predicate<IAuthorizationDecisionCacheKey> predicate );

/**
* Clears all cached authorization decisions.
* <p>
* This operation is a no-op if the cache is disabled.
*/
void invalidateAll();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*! ******************************************************************************
*
* Pentaho
*
* Copyright (C) 2024 by Hitachi Vantara, LLC : http://www.pentaho.com
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file.
*
* Change Date: 2029-07-20
******************************************************************************/

package org.pentaho.platform.api.engine.security.authorization.caching;

import edu.umd.cs.findbugs.annotations.NonNull;
import org.pentaho.platform.api.engine.security.authorization.IAuthorizationOptions;
import org.pentaho.platform.api.engine.security.authorization.IAuthorizationRequest;

/**
* The {@code IAuthorizationDecisionCacheKey} interface represents the key for cached authorization decision.
* It is constituted by an authorization request and options.
* <p>
* Implementations must implement proper {@code equals()} and {@code hashCode()} methods.
*/
public interface IAuthorizationDecisionCacheKey {
@NonNull
IAuthorizationRequest getRequest();

@NonNull
IAuthorizationOptions getOptions();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*! ******************************************************************************
*
* Pentaho
*
* Copyright (C) 2024 by Hitachi Vantara, LLC : http://www.pentaho.com
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file.
*
* Change Date: 2029-07-20
******************************************************************************/

package org.pentaho.platform.api.engine.security.authorization.impl;

import edu.umd.cs.findbugs.annotations.NonNull;
import org.pentaho.platform.api.engine.security.authorization.AuthorizationDecisionReportingMode;
import org.pentaho.platform.api.engine.security.authorization.IAuthorizationOptions;

/**
* The {@code DefaultAuthorizationOptions} class provides an implementation of {@link IAuthorizationOptions} with the
* default option values.
* <p>
* This class is intended for internal use.
* It supports the implementation of the {@link IAuthorizationOptions#getDefault()} method.
*/
public class DefaultAuthorizationOptions implements IAuthorizationOptions {

Check notice on line 26 in api/src/main/java/org/pentaho/platform/api/engine/security/authorization/impl/DefaultAuthorizationOptions.java

View check run for this annotation

HitachiVantaraSonarQube / Pentaho BI Platform Community Edition Sonarqube Results

api/src/main/java/org/pentaho/platform/api/engine/security/authorization/impl/DefaultAuthorizationOptions.java#L26

A Singleton implementation was detected. Make sure the use of the Singleton pattern is required and the implementation is the right one for the context.

public static final DefaultAuthorizationOptions INSTANCE = new DefaultAuthorizationOptions();

private DefaultAuthorizationOptions() {
// Prevent external instantiation.
}

@NonNull
@Override
public AuthorizationDecisionReportingMode getDecisionReportingMode() {
return AuthorizationDecisionReportingMode.SETTLED;
}

@Override
public boolean equals( Object obj ) {
if ( this == obj ) {
return true;
}

if ( !( obj instanceof IAuthorizationOptions other ) ) {
return false;
}

return getDecisionReportingMode() == other.getDecisionReportingMode();
}

@Override
public int hashCode() {
return getDecisionReportingMode().hashCode();
}

@Override
public String toString() {
return String.format(
"IAuthorizationOptions{decisionReportingMode=%s}",
getDecisionReportingMode() );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,9 @@
GET /api/system/refresh/reportingDataCache
GET /api/system/refresh/mondrianSingleSchemaCache
GET /api/system/refresh/mondrianSchemaCache
GET /api/system/refresh/authorizationDecisionCache
-->
<swm:regex-request-matcher pattern="^/api/system/refresh/(globalActions|metadata|systemSettings|reportingDataCache|mondrianSingleSchemaCache|mondrianSchemaCache)\b.*" methods="GET" />
<swm:regex-request-matcher pattern="^/api/system/refresh/(globalActions|metadata|systemSettings|reportingDataCache|mondrianSingleSchemaCache|mondrianSchemaCache|authorizationDecisionCache)\b.*" methods="GET" />

<!--
POST /api/licenseManager/addLicense
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,14 @@ not directly from the PentahoObjectFactory. -->
</pen:publish>
</bean>

<!-- Legacy IAuthorizationPolicy implementation that delegates to IAuthorizationService -->
<bean id="authorizationPolicy"
class="org.pentaho.platform.engine.security.authorization.AuthorizationServiceAuthorizationPolicy">
<constructor-arg ref="authorizationActionService"/>
<constructor-arg ref="authorizationService"/>
<constructor-arg ref="currentAuthorizationUserSupplier"/>
</bean>

<bean id="currentAuthorizationUserSupplier"
class="org.pentaho.platform.engine.security.authorization.spring.SpringSecurityContextAuthorizationUserSupplier">
</bean>
Expand All @@ -326,13 +334,42 @@ not directly from the PentahoObjectFactory. -->

<bean id="authorizationActionService"
class="org.pentaho.platform.engine.security.authorization.PentahoSystemAuthorizationActionService">
<constructor-arg ref="IPluginManager" />
<pen:publish as-type="INTERFACES" />
</bean>

<bean id="authorizationDecisionCache"
class="org.pentaho.platform.engine.security.authorization.core.caching.MemoryAuthorizationDecisionCache">
<!-- expireAfterWrite: Max number of seconds that an auth entry stays cached.
Warning: this can only be set to a high value (e.g. several minutes or more) if operations that change any
variables that affect authorization decisions (e.g. user roles, resource permissions, etc.) also perform
cache invalidation. This is the case of the default Pentaho platform Security Provider implementation,
which appropriately invalidates the authorizations cache whenever a user's roles change.
When an external security provider is configured, either a lower, acceptable value is used (e.g. 2 seconds),
or a custom invalidation mechanism must be sought. Full manual invalidation of the cache can be done via
endpoint or PUC UI -->
<constructor-arg value="300" />

<!-- maximumSize: Max number of auth entries the cache can hold, _per session_ -->
<constructor-arg value="100" />

<!-- recordStats: Enable statistics recording. To be used for diagnostics and configuration fine-tuning, along with
enabling logging of the 'org.pentaho.platform.engine.security.authorization' package at TRACE level. -->
<constructor-arg value="false" />

<!-- staleSessionsSweepInterval: number of seconds between sweeps to remove stale session caches. Provided as a
fallback mechanism to deal with misbehaved code that does not explicitly destroy Pentaho sessions.
A value of 0 or less disables this feature. Class logs a warning whenever stale entries are detected. -->
<constructor-arg value="240" />

<pen:publish as-type="INTERFACES" />
</bean>

<bean id="authorizationService"
class="org.pentaho.platform.engine.security.authorization.core.AuthorizationService">
class="org.pentaho.platform.engine.security.authorization.core.CachingAuthorizationService">
<constructor-arg ref="authorizationActionService" />
<constructor-arg ref="rootAuthorizationRule" />
<constructor-arg ref="authorizationDecisionCache" />
<pen:publish as-type="INTERFACES" />
</bean>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@
<constructor-arg ref="singleTenantSystemAuthorities"/>
<constructor-arg ref="extraRoles"/>
<constructor-arg ref="jCacheUserCache"/>
<constructor-arg ref="authorizationDecisionCache" />
</bean>

<!--
Expand Down Expand Up @@ -716,22 +717,6 @@
</bean>

<!-- begin authorization policy -->

<bean id="authorizationPolicy" class="org.pentaho.platform.security.policy.rolebased.RoleAuthorizationPolicy">
<!--
authorization policy should not be blocked by security checks (because it is involved in doing the security
checks!)
-->
<constructor-arg ref="roleAuthorizationPolicyRoleBindingDaoTxn"/>
</bean>
<!-- TODO: uncomment this, and remove above bean, to switch to the new authorization policy implementation.
<bean id="authorizationPolicy"
class="org.pentaho.platform.engine.security.authorization.AuthorizationServiceAuthorizationPolicy">
<constructor-arg ref="authorizationActionService"/>
<constructor-arg ref="authorizationService"/>
<constructor-arg ref="currentAuthorizationUserSupplier"/>
</bean>
-->
<util:map id="immutableRoleBindingMap">
<entry key-ref="singleTenantAdminAuthorityName">
<pen:list class="org.pentaho.platform.api.engine.IAuthorizationAction"/>
Expand Down Expand Up @@ -769,6 +754,7 @@
<constructor-arg>
<pen:list class="org.pentaho.platform.api.engine.IAuthorizationAction"/>
</constructor-arg>
<constructor-arg ref="authorizationDecisionCache" />
</bean>

<!-- Built-In ABS Logical Roles -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
</bean>

<bean id="defaultContentSystemListener" class="org.pentaho.platform.plugin.action.defaultcontent.DefaultContentSystemListener" />
<bean id="memoryAuthorizationCacheSystemListener" class="org.pentaho.platform.engine.security.authorization.core.caching.MemoryAuthorizationDecisionCacheSystemListener">
<constructor-arg ref="authorizationDecisionCache" />
</bean>
<!-- Insert system-listeners -->
</list>
</constructor-arg>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
<Logger name="org.pentaho.di.monitor" level="ERROR"/>
<Logger name="org.pentaho.platform.engine.core.system.status" level="INFO"/>
<Logger name="org.pentaho.reporting.engine.classic.core.modules.output.fast.validator.ReportStructureValidator" level="INFO"/>
<Logger name="org.pentaho.platform.engine.security.authorization" level="ERROR"/>

<!-- =========================== -->
<!-- Repository Import Log Level -->
Expand Down
Loading