Skip to content
Draft
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 @@ -33,6 +33,17 @@ public interface IResourceAuthorizationRequest extends IAuthorizationRequest {
@NonNull
IAuthorizationRequest asGeneral();

/**
* Creates a resource-specific request, of type {@code IResourceSpecificAuthorizationRequest}, having the same user,
* action and resource.
* <p>
* If the current instance is already of type {@code IResourceSpecificAuthorizationRequest}, it is returned as-is.
*
* @return A corresponding specific resource request.
*/
@NonNull
IResourceSpecificAuthorizationRequest asSpecific();

/**
* Creates a new instance of {@code IResourceAuthorizationRequest} with the same user and action, but with a
* different resource.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*! ******************************************************************************
*
* 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.resources;

public interface IResourceSpecificAuthorizationRequest extends IResourceAuthorizationRequest {
}
Original file line number Diff line number Diff line change
Expand Up @@ -465,14 +465,21 @@ not directly from the PentahoObjectFactory. -->
</pen:attributes>
</pen:publish>
</bean>
<bean class="org.pentaho.platform.engine.security.authorization.core.rules.ResourceActionGeneralRequirementAuthorizationRule">
<bean class="org.pentaho.platform.engine.security.authorization.core.rules.ResourceGeneralAuthorizationRule">
<pen:publish as-type="INTERFACES">
<pen:attributes>
<pen:attr key="ruleLevel" value="veto"/>
<pen:attr key="priority" value="10"/>
</pen:attributes>
</pen:publish>
</bean>
<bean class="org.pentaho.platform.engine.security.authorization.core.rules.ResourceSpecificAuthorizationRule">
<pen:publish as-type="INTERFACES">
<pen:attributes>
<pen:attr key="priority" value="10"/>
</pen:attributes>
</pen:publish>
</bean>

<bean id="userConsoleService" class="org.pentaho.platform.web.http.api.resources.services.UserConsoleService">
<pen:publish as-type="CLASSES"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@
import org.pentaho.platform.api.engine.security.authorization.decisions.IAuthorizationDecision;
import org.pentaho.platform.engine.security.messages.Messages;

public class ResourceActionGeneralRequirementAuthorizationDecision extends DerivedAuthorizationDecision {
public class ResourceGeneralAuthorizationDecision extends DerivedAuthorizationDecision {
private static final String JUSTIFICATION =
Messages.getInstance().getString( "ResourceActionGeneralRequirementAuthorizationDecision.JUSTIFICATION" );
Messages.getInstance().getString( "ResourceGeneralAuthorizationDecision.JUSTIFICATION" );

public ResourceActionGeneralRequirementAuthorizationDecision( @NonNull
IAuthorizationRequest request,
@NonNull
IAuthorizationDecision derivedFromDecision ) {
public ResourceGeneralAuthorizationDecision( @NonNull IAuthorizationRequest request,
@NonNull IAuthorizationDecision derivedFromDecision ) {
super( request, derivedFromDecision );
}

Expand All @@ -25,7 +23,7 @@ public String getShortJustification() {

@Override
public String toString() {
// Example: "ResourceActionGeneralRequirementAuthorizationDecision[Granted, from: <general decision>]"
// Example: "ResourceGeneralAuthorizationDecision[Granted, from: <general decision>]"
return String.format(
"%s[%s, from: %s]",
getClass().getSimpleName(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.pentaho.platform.engine.security.authorization.core.decisions;

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

public class ResourceSpecificAuthorizationDecision extends DerivedAuthorizationDecision {
private static final String JUSTIFICATION =
Messages.getInstance().getString( "ResourceSpecificAuthorizationDecision.JUSTIFICATION" );

public ResourceSpecificAuthorizationDecision( @NonNull IAuthorizationRequest request,
@NonNull IAuthorizationDecision derivedFromDecision ) {
super( request, derivedFromDecision );
}

@NonNull
@Override
public String getShortJustification() {
// Example: "From specific permission"
return JUSTIFICATION;
}

@Override
public String toString() {
// Example: "ResourceSpecificAuthorizationDecision[Granted, from: <specific decision>]"
return String.format(
"%s[%s, from: %s]",
getClass().getSimpleName(),
getGrantedLogText(),
getDerivedFromDecision() );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import org.pentaho.platform.api.engine.IAuthorizationAction;
import org.pentaho.platform.api.engine.security.authorization.IAuthorizationRequest;
import org.pentaho.platform.api.engine.security.authorization.resources.IAuthorizationResource;
import org.pentaho.platform.api.engine.security.authorization.IAuthorizationUser;
import org.pentaho.platform.api.engine.security.authorization.resources.IAuthorizationResource;
import org.pentaho.platform.api.engine.security.authorization.resources.IResourceAuthorizationRequest;
import org.pentaho.platform.api.engine.security.authorization.resources.IResourceSpecificAuthorizationRequest;
import org.pentaho.platform.engine.security.authorization.core.AuthorizationRequest;

import java.util.Objects;
Expand Down Expand Up @@ -73,6 +74,12 @@ public IAuthorizationRequest asGeneral() {
return new AuthorizationRequest( getUser(), getAction() );
}

@NonNull
@Override
public IResourceSpecificAuthorizationRequest asSpecific() {
return new ResourceSpecificAuthorizationRequest( this );
}

@Override
public boolean equals( Object o ) {
if ( !super.equals( o ) ) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*! ******************************************************************************
*
* 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.engine.security.authorization.core.resources;

import edu.umd.cs.findbugs.annotations.NonNull;
import org.pentaho.platform.api.engine.IAuthorizationAction;
import org.pentaho.platform.api.engine.security.authorization.IAuthorizationUser;
import org.pentaho.platform.api.engine.security.authorization.resources.IAuthorizationResource;
import org.pentaho.platform.api.engine.security.authorization.resources.IResourceAuthorizationRequest;
import org.pentaho.platform.api.engine.security.authorization.resources.IResourceSpecificAuthorizationRequest;

/**
* The {@code ResourceSpecificAuthorizationRequest} class is a basic implementation of the
* {@link IResourceSpecificAuthorizationRequest} interface.
*/
public class ResourceSpecificAuthorizationRequest extends ResourceAuthorizationRequest
implements IResourceSpecificAuthorizationRequest {

/**
* Constructs an {@code ResourceSpecificAuthorizationRequest} with the specified user and action name.
*
* @param resourceRequest The resource request to initialize from.
*/
public ResourceSpecificAuthorizationRequest( @NonNull ResourceAuthorizationRequest resourceRequest ) {
super( resourceRequest.getUser(), resourceRequest.getAction(), resourceRequest.getResource() );
}

/**
* Constructs an {@code ResourceSpecificAuthorizationRequest} with the specified user and action name.
*
* @param user The user for whom the authorization is being evaluated.
* @param action The action to be evaluated.
* @param resource The resource for which the authorization is being evaluated.
*/
public ResourceSpecificAuthorizationRequest( @NonNull IAuthorizationUser user,
@NonNull IAuthorizationAction action,
@NonNull IAuthorizationResource resource ) {
super( user, action, resource );
}

@NonNull
@Override
public IResourceAuthorizationRequest withAction( @NonNull IAuthorizationAction action ) {
return new ResourceSpecificAuthorizationRequest( getUser(), action, getResource() );
}

@NonNull
@Override
public IResourceAuthorizationRequest withResource( @NonNull IAuthorizationResource resource ) {
return new ResourceSpecificAuthorizationRequest( getUser(), getAction(), resource );
}

@NonNull
@Override
public IResourceSpecificAuthorizationRequest asSpecific() {
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
import org.pentaho.platform.api.engine.security.authorization.IAuthorizationContext;
import org.pentaho.platform.api.engine.security.authorization.decisions.IAuthorizationDecision;
import org.pentaho.platform.api.engine.security.authorization.resources.IResourceAuthorizationRequest;
import org.pentaho.platform.engine.security.authorization.core.decisions.ResourceActionGeneralRequirementAuthorizationDecision;
import org.pentaho.platform.api.engine.security.authorization.resources.IResourceSpecificAuthorizationRequest;
import org.pentaho.platform.engine.security.authorization.core.decisions.ResourceGeneralAuthorizationDecision;

import java.util.Optional;

public class ResourceActionGeneralRequirementAuthorizationRule
public class ResourceGeneralAuthorizationRule
extends AbstractAuthorizationRule<IResourceAuthorizationRequest> {

@NonNull
Expand All @@ -33,9 +34,13 @@ public Class<IResourceAuthorizationRequest> getRequestType() {
@Override
public Optional<IAuthorizationDecision> authorize( @NonNull IResourceAuthorizationRequest resourceRequest,
@NonNull IAuthorizationContext context ) {
if ( resourceRequest instanceof IResourceSpecificAuthorizationRequest ) {
return abstain();
}

// Dispatch a corresponding general request.
var generalRequest = resourceRequest.asGeneral();
var generalDecision = context.authorize( generalRequest );
return Optional.of( new ResourceActionGeneralRequirementAuthorizationDecision( resourceRequest, generalDecision ) );
return Optional.of( new ResourceGeneralAuthorizationDecision( resourceRequest, generalDecision ) );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*! ******************************************************************************
*
* 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.engine.security.authorization.core.rules;

import edu.umd.cs.findbugs.annotations.NonNull;
import org.pentaho.platform.api.engine.security.authorization.IAuthorizationContext;
import org.pentaho.platform.api.engine.security.authorization.decisions.IAuthorizationDecision;
import org.pentaho.platform.api.engine.security.authorization.resources.IResourceAuthorizationRequest;
import org.pentaho.platform.api.engine.security.authorization.resources.IResourceSpecificAuthorizationRequest;
import org.pentaho.platform.engine.security.authorization.core.decisions.ResourceSpecificAuthorizationDecision;

import java.util.Optional;

public class ResourceSpecificAuthorizationRule
extends AbstractAuthorizationRule<IResourceAuthorizationRequest> {

@NonNull
@Override
public Class<IResourceAuthorizationRequest> getRequestType() {
return IResourceAuthorizationRequest.class;
}

@NonNull
@Override
public Optional<IAuthorizationDecision> authorize( @NonNull IResourceAuthorizationRequest resourceRequest,
@NonNull IAuthorizationContext context ) {
// Rule only applies to abstract/effective/top-level resource requests
if ( resourceRequest instanceof IResourceSpecificAuthorizationRequest ) {
return abstain();
}

// Dispatch a corresponding specific request.
var specificRequest = resourceRequest.asSpecific();
var specificDecision = context.authorize( specificRequest );
return Optional.of( new ResourceSpecificAuthorizationDecision( resourceRequest, specificDecision ) );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ DerivedActionAuthorizationDecision.JUSTIFICATION=From operation {0}
# 0 - the role name
MatchedRoleAuthorizationDecision.JUSTIFICATION=Has role {0}

ResourceActionGeneralRequirementAuthorizationDecision.JUSTIFICATION=From general permission
ResourceGeneralAuthorizationDecision.JUSTIFICATION=From general permission
ResourceSpecificAuthorizationDecision.JUSTIFICATION=From specific permission

AuthorizationErrorDecision.JUSTIFICATION=Authorization error
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class ResourceActionGeneralRequirementAuthorizationDecisionTest {
public class ResourceGeneralAuthorizationDecisionTest {

private IAuthorizationRequest request1;
private IAuthorizationRequest request2;
Expand Down Expand Up @@ -64,13 +64,13 @@ public void setUp() {
@Test
public void testConstructorAndGetters() {
var grantedRequirementDecision =
new ResourceActionGeneralRequirementAuthorizationDecision( request2, grantedDecision );
new ResourceGeneralAuthorizationDecision( request2, grantedDecision );
assertEquals( request2, grantedRequirementDecision.getRequest() );
assertTrue( grantedRequirementDecision.isGranted() );
assertSame( grantedDecision, grantedRequirementDecision.getDerivedFromDecision() );

var deniedRequirementDecision =
new ResourceActionGeneralRequirementAuthorizationDecision( request2, deniedDecision );
new ResourceGeneralAuthorizationDecision( request2, deniedDecision );
assertEquals( request2, deniedRequirementDecision.getRequest() );
assertFalse( deniedRequirementDecision.isGranted() );
assertSame( deniedDecision, deniedRequirementDecision.getDerivedFromDecision() );
Expand All @@ -79,23 +79,23 @@ public void testConstructorAndGetters() {
@Test( expected = NullPointerException.class )
public void testConstructorWithNullRequestThrows() {
//noinspection DataFlowIssue
new ResourceActionGeneralRequirementAuthorizationDecision( null, grantedDecision );
new ResourceGeneralAuthorizationDecision( null, grantedDecision );
}

@Test( expected = NullPointerException.class )
public void testConstructorWithNullDerivedFromDecisionThrows() {
//noinspection DataFlowIssue
new ResourceActionGeneralRequirementAuthorizationDecision( request2, null );
new ResourceGeneralAuthorizationDecision( request2, null );
}

@Test( expected = IllegalArgumentException.class )
public void testConstructorWithSameRequestThrows() {
new ResourceActionGeneralRequirementAuthorizationDecision( request1, grantedDecision );
new ResourceGeneralAuthorizationDecision( request1, grantedDecision );
}

@Test
public void testGetShortJustification() {
var requirementDecision = new ResourceActionGeneralRequirementAuthorizationDecision( request2, grantedDecision );
var requirementDecision = new ResourceGeneralAuthorizationDecision( request2, grantedDecision );
var justification = requirementDecision.getShortJustification();
assertNotNull( justification );
assertFalse( justification.isEmpty() );
Expand All @@ -104,19 +104,19 @@ public void testGetShortJustification() {
@Test
public void testToStringFormat() {
var grantedRequirementDecision =
new ResourceActionGeneralRequirementAuthorizationDecision( request2, grantedDecision );
new ResourceGeneralAuthorizationDecision( request2, grantedDecision );
var deniedRequirementDecision =
new ResourceActionGeneralRequirementAuthorizationDecision( request2, deniedDecision );
new ResourceGeneralAuthorizationDecision( request2, deniedDecision );

var grantedString = grantedRequirementDecision.toString();
var deniedString = deniedRequirementDecision.toString();

assertTrue( grantedString.contains( "ResourceActionGeneralRequirementAuthorizationDecision" ) );
assertTrue( grantedString.contains( "ResourceGeneralAuthorizationDecision" ) );
assertTrue( grantedString.contains( "Granted" ) );
assertTrue( grantedString.contains( "from:" ) );
assertTrue( grantedString.contains( "GrantedGeneralDecision" ) );

assertTrue( deniedString.contains( "ResourceActionGeneralRequirementAuthorizationDecision" ) );
assertTrue( deniedString.contains( "ResourceGeneralAuthorizationDecision" ) );
assertTrue( deniedString.contains( "Denied" ) );
assertTrue( deniedString.contains( "from:" ) );
assertTrue( deniedString.contains( "DeniedGeneralDecision" ) );
Expand Down
Loading