Skip to content

Commit 8690883

Browse files
authored
Merge pull request #6027 from dcleao/PPUC-122-6-TheSwitch
feat(auth): switch legacy IAuthorizationPolicy to IAuthorizationService impl [PPUC-318]
2 parents 5b7e45c + b231635 commit 8690883

File tree

37 files changed

+1865
-386
lines changed

37 files changed

+1865
-386
lines changed

api/src/main/java/org/pentaho/platform/api/engine/security/authorization/IAuthorizationActionService.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ default Stream<IAuthorizationAction> getActions( @Nullable String actionNamespac
6262
.filter( action -> action.getName().startsWith( actionNamespacePrefix ) );
6363
}
6464

65-
// TODO: tests
6665
/**
6766
* Gets an authorization action given its name.
6867
* <p>

api/src/main/java/org/pentaho/platform/api/engine/security/authorization/IAuthorizationOptions.java

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
package org.pentaho.platform.api.engine.security.authorization;
1414

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

1718
/**
1819
* The {@code IAuthorizationOptions} interface encapsulates options that control the authorization evaluation process.
@@ -34,39 +35,7 @@ public interface IAuthorizationOptions {
3435
* @return An instance of {@link IAuthorizationOptions}.
3536
*/
3637
static IAuthorizationOptions getDefault() {
37-
return new IAuthorizationOptions() {
38-
@NonNull
39-
@Override
40-
public AuthorizationDecisionReportingMode getDecisionReportingMode() {
41-
return AuthorizationDecisionReportingMode.SETTLED;
42-
}
43-
44-
@Override
45-
public boolean equals( Object obj ) {
46-
if ( this == obj ) {
47-
return true;
48-
}
49-
50-
if ( !( obj instanceof IAuthorizationOptions ) ) {
51-
return false;
52-
}
53-
54-
IAuthorizationOptions other = (IAuthorizationOptions) obj;
55-
return getDecisionReportingMode() == other.getDecisionReportingMode();
56-
}
57-
58-
@Override
59-
public int hashCode() {
60-
return getDecisionReportingMode().hashCode();
61-
}
62-
63-
@Override
64-
public String toString() {
65-
return String.format(
66-
"IAuthorizationOptions{decisionReportingMode=%s}",
67-
getDecisionReportingMode() );
68-
}
69-
};
38+
return DefaultAuthorizationOptions.INSTANCE;
7039
}
7140

7241
/**
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*! ******************************************************************************
2+
*
3+
* Pentaho
4+
*
5+
* Copyright (C) 2024 by Hitachi Vantara, LLC : http://www.pentaho.com
6+
*
7+
* Use of this software is governed by the Business Source License included
8+
* in the LICENSE.TXT file.
9+
*
10+
* Change Date: 2029-07-20
11+
******************************************************************************/
12+
13+
package org.pentaho.platform.api.engine.security.authorization.caching;
14+
15+
import edu.umd.cs.findbugs.annotations.NonNull;
16+
import org.pentaho.platform.api.engine.security.authorization.IAuthorizationOptions;
17+
import org.pentaho.platform.api.engine.security.authorization.IAuthorizationRequest;
18+
import org.pentaho.platform.api.engine.security.authorization.decisions.IAuthorizationDecision;
19+
20+
import java.util.Optional;
21+
import java.util.function.Function;
22+
import java.util.function.Predicate;
23+
24+
/**
25+
* The {@code IAuthorizationDecisionCache} interface represents a cache for authorization decisions,
26+
* and which follows the "loading cache" pattern.
27+
*/
28+
public interface IAuthorizationDecisionCache {
29+
/**
30+
* Gets a cached authorization decision for a specific authorization request and options, if available.
31+
*
32+
* @param request The authorization request.
33+
* @param options The authorization options.
34+
* @return An optional with the cached decision, if found; an empty optional, if not found.
35+
*/
36+
@NonNull
37+
Optional<IAuthorizationDecision> get( @NonNull IAuthorizationRequest request,
38+
@NonNull IAuthorizationOptions options );
39+
40+
/**
41+
* Gets a cached authorization decision for a specific authorization request and options,
42+
* loading it from the given loader function and storing it in the cache, if not available.
43+
*
44+
* @param request The authorization request.
45+
* @param options The authorization options.
46+
* @param loader A function that computes the authorization decision if it is not found in the cache.
47+
* @return The authorization decision.
48+
*/
49+
@NonNull
50+
IAuthorizationDecision get( @NonNull IAuthorizationRequest request,
51+
@NonNull IAuthorizationOptions options,
52+
@NonNull Function<IAuthorizationDecisionCacheKey, IAuthorizationDecision> loader );
53+
54+
/**
55+
* Caches an authorization decision for a specific authorization request and options.
56+
* <p>
57+
* This operation is a no-op if the cache is disabled.
58+
*
59+
* @param request The authorization request.
60+
* @param options The authorization options.
61+
* @param decision The authorization decision to cache.
62+
*/
63+
void put( @NonNull IAuthorizationRequest request,
64+
@NonNull IAuthorizationOptions options,
65+
@NonNull IAuthorizationDecision decision );
66+
67+
/**
68+
* Clears the cached authorization decision for a specific authorization request and options, if any.
69+
*
70+
* @param request The authorization request.
71+
* @param options The authorization options.
72+
*/
73+
void invalidate( @NonNull IAuthorizationRequest request, @NonNull IAuthorizationOptions options );
74+
75+
/**
76+
* Clears all cached authorization decisions for requests and options that match the given predicate.
77+
*
78+
* @param predicate A predicate that matches authorization requests and options to clear from the cache.
79+
*/
80+
void invalidateAll( @NonNull Predicate<IAuthorizationDecisionCacheKey> predicate );
81+
82+
/**
83+
* Clears all cached authorization decisions.
84+
* <p>
85+
* This operation is a no-op if the cache is disabled.
86+
*/
87+
void invalidateAll();
88+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*! ******************************************************************************
2+
*
3+
* Pentaho
4+
*
5+
* Copyright (C) 2024 by Hitachi Vantara, LLC : http://www.pentaho.com
6+
*
7+
* Use of this software is governed by the Business Source License included
8+
* in the LICENSE.TXT file.
9+
*
10+
* Change Date: 2029-07-20
11+
******************************************************************************/
12+
13+
package org.pentaho.platform.api.engine.security.authorization.caching;
14+
15+
import edu.umd.cs.findbugs.annotations.NonNull;
16+
import org.pentaho.platform.api.engine.security.authorization.IAuthorizationOptions;
17+
import org.pentaho.platform.api.engine.security.authorization.IAuthorizationRequest;
18+
19+
/**
20+
* The {@code IAuthorizationDecisionCacheKey} interface represents the key for cached authorization decision.
21+
* It is constituted by an authorization request and options.
22+
* <p>
23+
* Implementations must implement proper {@code equals()} and {@code hashCode()} methods.
24+
*/
25+
public interface IAuthorizationDecisionCacheKey {
26+
@NonNull
27+
IAuthorizationRequest getRequest();
28+
29+
@NonNull
30+
IAuthorizationOptions getOptions();
31+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*! ******************************************************************************
2+
*
3+
* Pentaho
4+
*
5+
* Copyright (C) 2024 by Hitachi Vantara, LLC : http://www.pentaho.com
6+
*
7+
* Use of this software is governed by the Business Source License included
8+
* in the LICENSE.TXT file.
9+
*
10+
* Change Date: 2029-07-20
11+
******************************************************************************/
12+
13+
package org.pentaho.platform.api.engine.security.authorization.impl;
14+
15+
import edu.umd.cs.findbugs.annotations.NonNull;
16+
import org.pentaho.platform.api.engine.security.authorization.AuthorizationDecisionReportingMode;
17+
import org.pentaho.platform.api.engine.security.authorization.IAuthorizationOptions;
18+
19+
/**
20+
* The {@code DefaultAuthorizationOptions} class provides an implementation of {@link IAuthorizationOptions} with the
21+
* default option values.
22+
* <p>
23+
* This class is intended for internal use.
24+
* It supports the implementation of the {@link IAuthorizationOptions#getDefault()} method.
25+
*/
26+
public class DefaultAuthorizationOptions implements IAuthorizationOptions {
27+
28+
public static final DefaultAuthorizationOptions INSTANCE = new DefaultAuthorizationOptions();
29+
30+
private DefaultAuthorizationOptions() {
31+
// Prevent external instantiation.
32+
}
33+
34+
@NonNull
35+
@Override
36+
public AuthorizationDecisionReportingMode getDecisionReportingMode() {
37+
return AuthorizationDecisionReportingMode.SETTLED;
38+
}
39+
40+
@Override
41+
public boolean equals( Object obj ) {
42+
if ( this == obj ) {
43+
return true;
44+
}
45+
46+
if ( !( obj instanceof IAuthorizationOptions other ) ) {
47+
return false;
48+
}
49+
50+
return getDecisionReportingMode() == other.getDecisionReportingMode();
51+
}
52+
53+
@Override
54+
public int hashCode() {
55+
return getDecisionReportingMode().hashCode();
56+
}
57+
58+
@Override
59+
public String toString() {
60+
return String.format(
61+
"IAuthorizationOptions{decisionReportingMode=%s}",
62+
getDecisionReportingMode() );
63+
}
64+
}

assemblies/pentaho-solutions/src/main/resources/pentaho-solutions/system/applicationContext-spring-security-csrf.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,9 @@
5656
GET /api/system/refresh/reportingDataCache
5757
GET /api/system/refresh/mondrianSingleSchemaCache
5858
GET /api/system/refresh/mondrianSchemaCache
59+
GET /api/system/refresh/authorizationDecisionCache
5960
-->
60-
<swm:regex-request-matcher pattern="^/api/system/refresh/(globalActions|metadata|systemSettings|reportingDataCache|mondrianSingleSchemaCache|mondrianSchemaCache)\b.*" methods="GET" />
61+
<swm:regex-request-matcher pattern="^/api/system/refresh/(globalActions|metadata|systemSettings|reportingDataCache|mondrianSingleSchemaCache|mondrianSchemaCache|authorizationDecisionCache)\b.*" methods="GET" />
6162

6263
<!--
6364
POST /api/licenseManager/addLicense

assemblies/pentaho-solutions/src/main/resources/pentaho-solutions/system/pentahoObjects.spring.xml

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,14 @@ not directly from the PentahoObjectFactory. -->
313313
</pen:publish>
314314
</bean>
315315

316+
<!-- Legacy IAuthorizationPolicy implementation that delegates to IAuthorizationService -->
317+
<bean id="authorizationPolicy"
318+
class="org.pentaho.platform.engine.security.authorization.AuthorizationServiceAuthorizationPolicy">
319+
<constructor-arg ref="authorizationActionService"/>
320+
<constructor-arg ref="authorizationService"/>
321+
<constructor-arg ref="currentAuthorizationUserSupplier"/>
322+
</bean>
323+
316324
<bean id="currentAuthorizationUserSupplier"
317325
class="org.pentaho.platform.engine.security.authorization.spring.SpringSecurityContextAuthorizationUserSupplier">
318326
</bean>
@@ -326,13 +334,45 @@ not directly from the PentahoObjectFactory. -->
326334

327335
<bean id="authorizationActionService"
328336
class="org.pentaho.platform.engine.security.authorization.PentahoSystemAuthorizationActionService">
337+
<constructor-arg ref="IPluginManager" />
338+
<pen:publish as-type="INTERFACES" />
339+
</bean>
340+
341+
<bean id="authorizationDecisionCache"
342+
class="org.pentaho.platform.engine.security.authorization.core.caching.MemoryAuthorizationDecisionCache">
343+
<!-- expireAfterWrite: Max number of seconds that an auth entry stays cached.
344+
Warning: this can only be set to a high value (e.g. several minutes or more) if operations that change any
345+
variables that affect authorization decisions (e.g. user roles, resource permissions, etc.) also perform
346+
cache invalidation. This is the case of the default Pentaho platform Security Provider implementation,
347+
which appropriately invalidates the authorizations cache whenever a user's roles change.
348+
When an external security provider is configured, either a lower, acceptable value is used (e.g. 2 seconds),
349+
or a custom invalidation mechanism must be sought. Full manual invalidation of the cache can be done via
350+
endpoint or PUC UI -->
351+
<constructor-arg value="300" />
352+
353+
<!-- maximumSize: Max number of auth entries the cache can hold, _per session_ -->
354+
<constructor-arg value="100" />
355+
356+
<!-- recordStats: Enable statistics recording. To be used for diagnostics and configuration fine-tuning, along with
357+
enabling logging of the 'org.pentaho.platform.engine.security.authorization' package at TRACE level. -->
358+
<constructor-arg value="false" />
359+
360+
<!-- staleSessionsSweepInterval: number of seconds between sweeps to remove stale session caches. Provided as a
361+
fallback mechanism to deal with misbehaved code that does not explicitly destroy Pentaho sessions.
362+
A value of 0 or less disables this feature. Class logs a warning whenever stale entries are detected. -->
363+
<constructor-arg value="240" />
364+
329365
<pen:publish as-type="INTERFACES" />
330366
</bean>
331367

332368
<bean id="authorizationService"
333-
class="org.pentaho.platform.engine.security.authorization.core.AuthorizationService">
369+
class="org.pentaho.platform.engine.security.authorization.core.CachingAuthorizationService">
334370
<constructor-arg ref="authorizationActionService" />
335-
<constructor-arg ref="rootAuthorizationRule" />
371+
<constructor-arg ref="authorizationDecisionCache" />
372+
<!-- Setting the rootRule as a property, instead of as a constructor arg, allows rules themselves to depend on the
373+
authorizationService. While this does not appear to be a useful scenario, it is provided for flexibility, and
374+
might avoid some third-party usage issues implementing rules. -->
375+
<property name="rootRule" ref="rootAuthorizationRule" />
336376
<pen:publish as-type="INTERFACES" />
337377
</bean>
338378

assemblies/pentaho-solutions/src/main/resources/pentaho-solutions/system/repository.spring.xml

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@
317317
<constructor-arg ref="singleTenantSystemAuthorities"/>
318318
<constructor-arg ref="extraRoles"/>
319319
<constructor-arg ref="jCacheUserCache"/>
320+
<constructor-arg ref="authorizationDecisionCache" />
320321
</bean>
321322

322323
<!--
@@ -716,22 +717,6 @@
716717
</bean>
717718

718719
<!-- begin authorization policy -->
719-
720-
<bean id="authorizationPolicy" class="org.pentaho.platform.security.policy.rolebased.RoleAuthorizationPolicy">
721-
<!--
722-
authorization policy should not be blocked by security checks (because it is involved in doing the security
723-
checks!)
724-
-->
725-
<constructor-arg ref="roleAuthorizationPolicyRoleBindingDaoTxn"/>
726-
</bean>
727-
<!-- TODO: uncomment this, and remove above bean, to switch to the new authorization policy implementation.
728-
<bean id="authorizationPolicy"
729-
class="org.pentaho.platform.engine.security.authorization.AuthorizationServiceAuthorizationPolicy">
730-
<constructor-arg ref="authorizationActionService"/>
731-
<constructor-arg ref="authorizationService"/>
732-
<constructor-arg ref="currentAuthorizationUserSupplier"/>
733-
</bean>
734-
-->
735720
<util:map id="immutableRoleBindingMap">
736721
<entry key-ref="singleTenantAdminAuthorityName">
737722
<pen:list class="org.pentaho.platform.api.engine.IAuthorizationAction"/>
@@ -769,6 +754,7 @@
769754
<constructor-arg>
770755
<pen:list class="org.pentaho.platform.api.engine.IAuthorizationAction"/>
771756
</constructor-arg>
757+
<constructor-arg ref="authorizationDecisionCache" />
772758
</bean>
773759

774760
<!-- Built-In ABS Logical Roles -->

assemblies/pentaho-solutions/src/main/resources/pentaho-solutions/system/systemListeners.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434
</bean>
3535

3636
<bean id="defaultContentSystemListener" class="org.pentaho.platform.plugin.action.defaultcontent.DefaultContentSystemListener" />
37+
<bean id="memoryAuthorizationCacheSystemListener" class="org.pentaho.platform.engine.security.authorization.core.caching.MemoryAuthorizationDecisionCacheSystemListener">
38+
<constructor-arg ref="authorizationDecisionCache" />
39+
</bean>
3740
<!-- Insert system-listeners -->
3841
</list>
3942
</constructor-arg>

assemblies/pentaho-war/src/main/webapp/WEB-INF/classes/log4j2.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@
126126
<Logger name="org.pentaho.di.monitor" level="ERROR"/>
127127
<Logger name="org.pentaho.platform.engine.core.system.status" level="INFO"/>
128128
<Logger name="org.pentaho.reporting.engine.classic.core.modules.output.fast.validator.ReportStructureValidator" level="INFO"/>
129+
<Logger name="org.pentaho.platform.engine.security.authorization" level="ERROR"/>
129130

130131
<!-- =========================== -->
131132
<!-- Repository Import Log Level -->

0 commit comments

Comments
 (0)