ACS-9178 Add REST API for deauthorizing (#3169)

* ACS-9178 Set peopleEntityResource bean id

* ACS-9178 Add the 'deauthorizeUser' operation

* ACS-9178 Add 'deauthorizeUser' to Rest API

* ACS-9178 Add test

* ACS-9178 Fix PMD

* ACS-9178 Fix deauthorize API tests

---------

Co-authored-by: Gerard Olenski <gerard.olenski@hyland.com>
This commit is contained in:
Damian Ujma
2025-01-30 11:07:57 +01:00
committed by GitHub
parent 6804d5e288
commit 733e232e42
4 changed files with 299 additions and 236 deletions

View File

@@ -437,6 +437,15 @@ public class People extends ModelRequest<People>
restWrapper.processEmptyModel(request); restWrapper.processEmptyModel(request);
} }
/**
* Deauthorize a user
*/
public void deauthorizeUser()
{
RestRequest request = RestRequest.simpleRequest(HttpMethod.POST, "people/{personId}/deauthorize", this.person.getUsername(), restWrapper.getParameters());
restWrapper.processEmptyModel(request);
}
/** /**
* Update avatar image PUT call on 'people/{nodeId}/children * Update avatar image PUT call on 'people/{nodeId}/children
*/ */
@@ -514,4 +523,4 @@ public class People extends ModelRequest<People>
return people.getFavorites(); return people.getFavorites();
} }
} }
} }

View File

@@ -0,0 +1,40 @@
package org.alfresco.rest.people.deauthorization.community;
import org.springframework.http.HttpStatus;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.alfresco.rest.RestTest;
import org.alfresco.utility.model.TestGroup;
import org.alfresco.utility.model.UserModel;
import org.alfresco.utility.testrail.ExecutionType;
import org.alfresco.utility.testrail.annotation.TestRail;
/**
* Verifies API behavior in community edition. Should be excluded in enterprise edition.
*/
@Test
public class DeauthorizeSanityTests extends RestTest
{
private UserModel userModel;
private UserModel adminUser;
@BeforeClass(alwaysRun = true)
public void dataPreparation()
{
adminUser = dataUser.getAdminUser();
userModel = dataUser.createRandomTestUser();
}
@Test(groups = {TestGroup.REST_API, TestGroup.PEOPLE, TestGroup.SANITY})
@TestRail(section = {TestGroup.REST_API, TestGroup.PEOPLE}, executionType = ExecutionType.SANITY,
description = "Check if de-authorization is not implemented in Community Edition")
public void deauthorizationIsNotImplementedInCommunityEdition()
{
restClient.authenticateUser(adminUser).withCoreAPI().usingUser(userModel).deauthorizeUser();
restClient.assertStatusCodeIs(HttpStatus.NOT_IMPLEMENTED);
restClient.authenticateUser(userModel).withCoreAPI().usingUser(userModel).deauthorizeUser();
restClient.assertStatusCodeIs(HttpStatus.NOT_IMPLEMENTED);
}
}

View File

@@ -1,234 +1,248 @@
/* /*
* #%L * #%L
* Alfresco Remote API * Alfresco Remote API
* %% * %%
* Copyright (C) 2005 - 2023 Alfresco Software Limited * Copyright (C) 2005 - 2025 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is * the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms: * provided under the following open source license terms:
* *
* Alfresco is free software: you can redistribute it and/or modify * Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* Alfresco is distributed in the hope that it will be useful, * Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. * GNU Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L% * #L%
*/ */
package org.alfresco.rest.api.people; package org.alfresco.rest.api.people;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.InitializingBean;
import org.alfresco.model.ContentModel;
import org.alfresco.rest.api.People; import org.alfresco.model.ContentModel;
import org.alfresco.rest.api.model.Client; import org.alfresco.rest.api.People;
import org.alfresco.rest.api.model.PasswordReset; import org.alfresco.rest.api.model.Client;
import org.alfresco.rest.api.model.Person; import org.alfresco.rest.api.model.PasswordReset;
import org.alfresco.rest.framework.BinaryProperties; import org.alfresco.rest.api.model.Person;
import org.alfresco.rest.framework.Operation; import org.alfresco.rest.framework.BinaryProperties;
import org.alfresco.rest.framework.WebApiDescription; import org.alfresco.rest.framework.Operation;
import org.alfresco.rest.framework.WebApiNoAuth; import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.WebApiParam; import org.alfresco.rest.framework.WebApiNoAuth;
import org.alfresco.rest.framework.core.ResourceParameter; import org.alfresco.rest.framework.WebApiParam;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException; import org.alfresco.rest.framework.core.ResourceParameter;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.resource.EntityResource; import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.resource.actions.interfaces.BinaryResourceAction; import org.alfresco.rest.framework.resource.EntityResource;
import org.alfresco.rest.framework.resource.actions.interfaces.EntityResourceAction; import org.alfresco.rest.framework.resource.actions.interfaces.BinaryResourceAction;
import org.alfresco.rest.framework.resource.content.BasicContentInfo; import org.alfresco.rest.framework.resource.actions.interfaces.EntityResourceAction;
import org.alfresco.rest.framework.resource.content.BinaryResource; import org.alfresco.rest.framework.resource.content.BasicContentInfo;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.parameters.Parameters; import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.webscripts.WithResponse; import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.util.PropertyCheck; import org.alfresco.rest.framework.webscripts.WithResponse;
import org.apache.commons.logging.Log; import org.alfresco.util.PropertyCheck;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean; /**
* An implementation of an Entity Resource for a Person
/** *
* An implementation of an Entity Resource for a Person * @author sglover
* * @author Gethin James
* @author sglover */
* @author Gethin James @EntityResource(name = "people", title = "People")
*/ public class PeopleEntityResource implements EntityResourceAction.ReadById<Person>, EntityResourceAction.Create<Person>,
@EntityResource(name="people", title = "People") EntityResourceAction.Update<Person>, EntityResourceAction.Read<Person>,
public class PeopleEntityResource implements EntityResourceAction.ReadById<Person>, EntityResourceAction.Create<Person>,
EntityResourceAction.Update<Person>,EntityResourceAction.Read<Person>, BinaryResourceAction.Read, BinaryResourceAction.Update<Person>, BinaryResourceAction.Delete, InitializingBean
{
BinaryResourceAction.Read, BinaryResourceAction.Update<Person>, BinaryResourceAction.Delete, InitializingBean private People people;
{
private static Log logger = LogFactory.getLog(PeopleEntityResource.class); public void setPeople(People people)
{
private People people; this.people = people;
}
public void setPeople(People people)
{ @Override
this.people = people; public void afterPropertiesSet()
} {
PropertyCheck.mandatory(this, "people", people);
@Override }
public void afterPropertiesSet()
{ /**
PropertyCheck.mandatory(this, "people", people); * Get a person by userName.
} *
* @see org.alfresco.rest.framework.resource.actions.interfaces.EntityResourceAction.ReadById#readById(String, org.alfresco.rest.framework.resource.parameters.Parameters)
/** */
* Get a person by userName. @Override
* @WebApiDescription(title = "Get Person Information", description = "Get information for the person with id 'personId'")
* @see org.alfresco.rest.framework.resource.actions.interfaces.EntityResourceAction.ReadById#readById(String, org.alfresco.rest.framework.resource.parameters.Parameters) @WebApiParam(name = "personId", title = "The person's username")
*/ public Person readById(String personId, Parameters parameters)
@Override {
@WebApiDescription(title = "Get Person Information", description = "Get information for the person with id 'personId'") Person person = people.getPerson(personId);
@WebApiParam(name = "personId", title = "The person's username") return person;
public Person readById(String personId, Parameters parameters) }
{
Person person = people.getPerson(personId); @Override
return person; @WebApiDescription(title = "Create person", description = "Create a person")
} @WebApiParam(name = "persons", title = "A single person", description = "A single person, multiple people are not supported.",
kind = ResourceParameter.KIND.HTTP_BODY_OBJECT, allowMultiple = false, required = true)
@Override public List<Person> create(List<Person> persons, Parameters parameters)
@WebApiDescription(title="Create person", description="Create a person") {
@WebApiParam(name="persons", title="A single person", description="A single person, multiple people are not supported.", Person p = persons.get(0);
kind= ResourceParameter.KIND.HTTP_BODY_OBJECT, allowMultiple=false, required = true)
public List<Person> create(List<Person> persons, Parameters parameters) validateDerivedFieldsExistence(p);
{
Person p = persons.get(0); List<Person> result = new ArrayList<>(1);
result.add(people.create(p));
validateDerivedFieldsExistence(p); return result;
}
List<Person> result = new ArrayList<>(1);
result.add(people.create(p)); @Override
return result; @WebApiDescription(title = "Update person", description = "Update the given person's details")
} public Person update(String personId, Person person, Parameters parameters)
{
@Override if (person.wasSet(ContentModel.PROP_USERNAME))
@WebApiDescription(title="Update person", description="Update the given person's details") {
public Person update(String personId, Person person, Parameters parameters) // REPO-1537
{ throw new InvalidArgumentException("Unsupported field: id");
if (person.wasSet(ContentModel.PROP_USERNAME)) }
{
// REPO-1537 validateDerivedFieldsExistence(person);
throw new InvalidArgumentException("Unsupported field: id");
} return people.update(personId, person);
}
validateDerivedFieldsExistence(person);
/**
return people.update(personId, person); * Explicitly test for the presence of system-maintained (derived) fields that are settable on Person (see also REPO-110).
} *
* @param person
/** */
* Explicitly test for the presence of system-maintained (derived) fields that are settable on Person (see also REPO-110). private void validateDerivedFieldsExistence(Person person)
* {
* @param person if (person.wasSet(ContentModel.PROP_USER_STATUS_TIME))
*/ {
private void validateDerivedFieldsExistence(Person person) throw new InvalidArgumentException("Unsupported field: statusUpdatedAt");
{ }
if (person.wasSet(ContentModel.PROP_USER_STATUS_TIME))
{ if (person.wasSet(Person.PROP_PERSON_AVATAR_ID))
throw new InvalidArgumentException("Unsupported field: statusUpdatedAt"); {
} throw new InvalidArgumentException("Unsupported field: avatarId");
}
if (person.wasSet(Person.PROP_PERSON_AVATAR_ID))
{ if (person.wasSet(ContentModel.PROP_SIZE_QUOTA))
throw new InvalidArgumentException("Unsupported field: avatarId"); {
} throw new InvalidArgumentException("Unsupported field: quota");
}
if (person.wasSet(ContentModel.PROP_SIZE_QUOTA))
{ if (person.wasSet(ContentModel.PROP_SIZE_CURRENT))
throw new InvalidArgumentException("Unsupported field: quota"); {
} throw new InvalidArgumentException("Unsupported field: quotaUsed");
}
if (person.wasSet(ContentModel.PROP_SIZE_CURRENT)) }
{
throw new InvalidArgumentException("Unsupported field: quotaUsed"); @Override
} @WebApiDescription(title = "Get List of People", description = "Get List of People")
} public CollectionWithPagingInfo<Person> readAll(Parameters params)
{
@Override return people.getPeople(params);
@WebApiDescription(title = "Get List of People", description = "Get List of People") }
public CollectionWithPagingInfo<Person> readAll(Parameters params)
{ @Deprecated
return people.getPeople(params); @Operation("request-password-reset")
} @WebApiDescription(title = "Request Password Reset", description = "Request password reset",
successStatus = HttpServletResponse.SC_ACCEPTED)
@Deprecated @WebApiNoAuth
@Operation("request-password-reset") public void requestPasswordReset(String personId, Client client, Parameters parameters, WithResponse withResponse)
@WebApiDescription(title = "Request Password Reset", description = "Request password reset", {
successStatus = HttpServletResponse.SC_ACCEPTED) people.requestPasswordReset(personId, client.getClient());
@WebApiNoAuth }
public void requestPasswordReset(String personId, Client client, Parameters parameters, WithResponse withResponse)
{ @Deprecated
people.requestPasswordReset(personId, client.getClient()); @Operation("reset-password")
} @WebApiDescription(title = "Reset Password", description = "Performs password reset", successStatus = HttpServletResponse.SC_ACCEPTED)
@WebApiNoAuth
@Deprecated public void resetPassword(String personId, PasswordReset passwordReset, Parameters parameters, WithResponse withResponse)
@Operation("reset-password") {
@WebApiDescription(title = "Reset Password", description = "Performs password reset", successStatus = HttpServletResponse.SC_ACCEPTED) people.resetPassword(personId, passwordReset);
@WebApiNoAuth }
public void resetPassword(String personId, PasswordReset passwordReset, Parameters parameters, WithResponse withResponse)
{ /**
people.resetPassword(personId, passwordReset); * Download avatar image content
} *
* @param personId
/** * @param parameters
* Download avatar image content * {@link Parameters}
* * @return
* @param personId * @throws EntityNotFoundException
* @param parameters {@link Parameters} */
* @return @Override
* @throws EntityNotFoundException @WebApiDescription(title = "Download avatar", description = "Download avatar")
*/ @BinaryProperties({"avatar"})
@Override public BinaryResource readProperty(String personId, Parameters parameters) throws EntityNotFoundException
@WebApiDescription(title = "Download avatar", description = "Download avatar") {
@BinaryProperties({"avatar"}) return people.downloadAvatarContent(personId, parameters);
public BinaryResource readProperty(String personId, Parameters parameters) throws EntityNotFoundException }
{
return people.downloadAvatarContent(personId, parameters); /**
} * Upload avatar image content
*
/** * @param personId
* Upload avatar image content * @param contentInfo
* * Basic information about the content stream
* @param personId * @param stream
* @param contentInfo Basic information about the content stream * An inputstream
* @param stream An inputstream * @param parameters
* @param parameters * @return
* @return */
*/ @Override
@Override @WebApiDescription(title = "Upload avatar", description = "Upload avatar")
@WebApiDescription(title = "Upload avatar", description = "Upload avatar") @BinaryProperties({"avatar"})
@BinaryProperties({"avatar"}) public Person updateProperty(String personId, BasicContentInfo contentInfo, InputStream stream, Parameters parameters)
public Person updateProperty(String personId, BasicContentInfo contentInfo, InputStream stream, Parameters parameters) {
{ return people.uploadAvatarContent(personId, contentInfo, stream, parameters);
return people.uploadAvatarContent(personId, contentInfo, stream, parameters); }
}
/**
/** * Delete avatar image content
* Delete avatar image content *
* * @param personId
* @param personId * @param parameters
* @param parameters * @return
* @return */
*/ @Override
@Override @WebApiDescription(title = "Delete avatar image", description = "Delete avatar image")
@WebApiDescription(title = "Delete avatar image", description = "Delete avatar image") @BinaryProperties({"avatar"})
@BinaryProperties({ "avatar" }) public void deleteProperty(String personId, Parameters parameters)
public void deleteProperty(String personId, Parameters parameters) {
{ people.deleteAvatarContent(personId);
people.deleteAvatarContent(personId); }
}
/**
* De-authorize user
} *
* Not currently supported in community edition.
*
* @param personId
* @param body
* @param parameters
* @param withResponse
*/
@Operation("deauthorize")
@WebApiDescription(title = "De-authorize user", description = "Performs user de-authorization", successStatus = HttpServletResponse.SC_NOT_IMPLEMENTED)
public void deauthorizeUser(String personId, Void body, Parameters parameters, WithResponse withResponse)
{
// functionality is not implemented in community edition
}
}

View File

@@ -1116,7 +1116,7 @@
<property name="siteMembershipRequests" ref="SiteMembershipRequests" /> <property name="siteMembershipRequests" ref="SiteMembershipRequests" />
</bean> </bean>
<bean class="org.alfresco.rest.api.people.PeopleEntityResource"> <bean id="peopleEntityResource" class="org.alfresco.rest.api.people.PeopleEntityResource">
<property name="people" ref="People" /> <property name="people" ref="People" />
</bean> </bean>