Merged 5.2.N (5.2.2) to HEAD (5.2)

135565 jkaabimofrad: Merged WEBAPP-API (5.2.1) to 5.2.N (5.2.1)
      135229 jkaabimofrad: APPSREPO-136: Updated the API framework so that WebApiNoAuth annotation can be used with operations.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@137401 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Andrei Rebegea
2017-06-14 17:07:13 +00:00
parent 25c8c95298
commit 67402ac66d
6 changed files with 121 additions and 55 deletions

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Remote API * Alfresco Remote API
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2017 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
@@ -28,9 +28,11 @@ package org.alfresco.rest.api;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.Serializable; import java.io.Serializable;
import java.util.*; import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import org.alfresco.rest.api.authentications.AuthenticationTicketsEntityResource;
import org.alfresco.rest.framework.Api; import org.alfresco.rest.framework.Api;
import org.alfresco.rest.framework.core.ResourceLocator; import org.alfresco.rest.framework.core.ResourceLocator;
import org.alfresco.rest.framework.core.ResourceWithMetadata; import org.alfresco.rest.framework.core.ResourceWithMetadata;
@@ -53,13 +55,14 @@ import org.springframework.http.HttpMethod;
* *
* @author steveglover * @author steveglover
* @author janv * @author janv
* @author Jamal Kaabi-Mofrad
* @since PublicApi1.0 * @since PublicApi1.0
*/ */
public class PublicApiDeclarativeRegistry extends DeclarativeRegistry public class PublicApiDeclarativeRegistry extends DeclarativeRegistry
{ {
private WebScript getNetworksWebScript; private WebScript getNetworksWebScript;
private WebScript getNetworkWebScript; private WebScript getNetworkWebScript;
private Container container; private Container container;
private ResourceLocator locator; private ResourceLocator locator;
@@ -70,21 +73,21 @@ public class PublicApiDeclarativeRegistry extends DeclarativeRegistry
public void setGetNetworksWebScript(WebScript getNetworksWebScript) public void setGetNetworksWebScript(WebScript getNetworksWebScript)
{ {
this.getNetworksWebScript = getNetworksWebScript; this.getNetworksWebScript = getNetworksWebScript;
} }
public void setGetNetworkWebScript(WebScript getNetworkWebScript) public void setGetNetworkWebScript(WebScript getNetworkWebScript)
{ {
this.getNetworkWebScript = getNetworkWebScript; this.getNetworkWebScript = getNetworkWebScript;
} }
public void setContainer(Container container) public void setContainer(Container container)
{ {
super.setContainer(container); super.setContainer(container);
this.container = container; this.container = container;
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see org.alfresco.web.scripts.Registry#findWebScript(java.lang.String, java.lang.String) * @see org.alfresco.web.scripts.Registry#findWebScript(java.lang.String, java.lang.String)
*/ */
public Match findWebScript(String method, String uri) public Match findWebScript(String method, String uri)
@@ -189,17 +192,46 @@ public class PublicApiDeclarativeRegistry extends DeclarativeRegistry
else if (HttpMethod.POST.equals(httpMethod)) else if (HttpMethod.POST.equals(httpMethod))
{ {
match = super.findWebScript(method, uri); match = super.findWebScript(method, uri);
if (match != null && uri.endsWith(AuthenticationTicketsEntityResource.COLLECTION_RESOURCE_NAME)) if (match != null)
{ {
ResourceWithMetadata rwm = getResourceWithMetadataOrNull(match.getTemplateVars(), httpMethod); ResourceWithMetadata rwm = getResourceWithMetadataOrNull(match.getTemplateVars(), httpMethod);
if (rwm != null && AuthenticationTicketsEntityResource.class.equals(rwm.getResource().getClass())) if (rwm != null)
{ {
Class<? extends ResourceAction> resAction = null; Class<? extends ResourceAction> resAction = null;
if (EntityResourceAction.Create.class.isAssignableFrom(rwm.getResource().getClass())) Boolean noAuth = null;
switch (rwm.getMetaData().getType())
{ {
resAction = EntityResourceAction.Create.class; case ENTITY:
if (EntityResourceAction.Create.class.isAssignableFrom(rwm.getResource().getClass()))
{
resAction = EntityResourceAction.Create.class;
}
else if (EntityResourceAction.CreateWithResponse.class.isAssignableFrom(rwm.getResource().getClass()))
{
resAction = EntityResourceAction.CreateWithResponse.class;
}
break;
case RELATIONSHIP:
if (RelationshipResourceAction.Create.class.isAssignableFrom(rwm.getResource().getClass()))
{
resAction = RelationshipResourceAction.Create.class;
}
else if (RelationshipResourceAction.CreateWithResponse.class.isAssignableFrom(rwm.getResource().getClass()))
{
resAction = RelationshipResourceAction.CreateWithResponse.class;
}
break;
case OPERATION:
noAuth = rwm.getMetaData().isNoAuth(null);
break;
default:
break;
} }
final boolean noAuth = (resAction != null && rwm.getMetaData().isNoAuth(resAction));
if (noAuth == null)
{
noAuth = (resAction != null && rwm.getMetaData().isNoAuth(resAction));
}
if (noAuth) if (noAuth)
{ {
// override match with noAuth // override match with noAuth
@@ -224,7 +256,7 @@ public class PublicApiDeclarativeRegistry extends DeclarativeRegistry
{ {
if (templateVars.get("apiName") != null) if (templateVars.get("apiName") != null)
{ {
// NOTE: noAuth currently only exposed for GET or Create Ticket (login) // NOTE: noAuth currently only exposed for GET or POST
Api api = ApiAssistant.determineApi(templateVars); Api api = ApiAssistant.determineApi(templateVars);
// TODO can we avoid locating resource more than once (or at least provide a common code to determine the GET resourceAction) ? // TODO can we avoid locating resource more than once (or at least provide a common code to determine the GET resourceAction) ?
@@ -439,23 +471,23 @@ public class PublicApiDeclarativeRegistry extends DeclarativeRegistry
private void initWebScript(WebScript webScript, String name) private void initWebScript(WebScript webScript, String name)
{ {
DescriptionImpl serviceDesc = new DescriptionImpl(name, name, name, name); DescriptionImpl serviceDesc = new DescriptionImpl(name, name, name, name);
serviceDesc.setRequiredAuthentication(RequiredAuthentication.user); serviceDesc.setRequiredAuthentication(RequiredAuthentication.user);
TransactionParameters transactionParameters = new TransactionParameters(); TransactionParameters transactionParameters = new TransactionParameters();
transactionParameters.setRequired(RequiredTransaction.required); transactionParameters.setRequired(RequiredTransaction.required);
transactionParameters.setCapability(TransactionCapability.readonly); transactionParameters.setCapability(TransactionCapability.readonly);
serviceDesc.setRequiredTransactionParameters(transactionParameters); serviceDesc.setRequiredTransactionParameters(transactionParameters);
serviceDesc.setFormatStyle(FormatStyle.argument); serviceDesc.setFormatStyle(FormatStyle.argument);
serviceDesc.setDefaultFormat("json"); serviceDesc.setDefaultFormat("json");
serviceDesc.setUris(new String[] { name }); serviceDesc.setUris(new String[] { name });
webScript.init(container, serviceDesc); webScript.init(container, serviceDesc);
} }
public void reset() public void reset()
{ {
super.reset(); super.reset();
initWebScript(getNetworksWebScript, "networks"); initWebScript(getNetworksWebScript, "networks");
initWebScript(getNetworkWebScript, "network"); initWebScript(getNetworkWebScript, "network");
} }
} }

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Remote API * Alfresco Remote API
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2017 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
@@ -40,6 +40,7 @@ import java.util.Set;
public class OperationResourceMetaData extends ResourceMetadata public class OperationResourceMetaData extends ResourceMetadata
{ {
private final Method operationMethod; private final Method operationMethod;
private final boolean noAuthRequired;
/** /**
* Use this constructor to create the resource metadata * Use this constructor to create the resource metadata
@@ -47,8 +48,9 @@ public class OperationResourceMetaData extends ResourceMetadata
* @param operations * @param operations
* @param api * @param api
* @param operationMethod * @param operationMethod
* @param noAuthRequired
*/ */
public OperationResourceMetaData(String uniqueId, List<ResourceOperation> operations, Api api, Method operationMethod) public OperationResourceMetaData(String uniqueId, List<ResourceOperation> operations, Api api, Method operationMethod, boolean noAuthRequired)
{ {
super(uniqueId, RESOURCE_TYPE.OPERATION, operations, api, null, null, null); super(uniqueId, RESOURCE_TYPE.OPERATION, operations, api, null, null, null);
if (operations.size()!= 1) if (operations.size()!= 1)
@@ -56,6 +58,7 @@ public class OperationResourceMetaData extends ResourceMetadata
throw new IllegalArgumentException("Only 1 operation per url is supported for an entity"); throw new IllegalArgumentException("Only 1 operation per url is supported for an entity");
} }
this.operationMethod = operationMethod; this.operationMethod = operationMethod;
this.noAuthRequired = noAuthRequired;
} }
/** /**
@@ -63,11 +66,13 @@ public class OperationResourceMetaData extends ResourceMetadata
* @param uniqueId * @param uniqueId
* @param api * @param api
* @param apiDeleted * @param apiDeleted
* @param noAuthRequired
*/ */
public OperationResourceMetaData(String uniqueId, Api api, Set<Class<? extends ResourceAction>> apiDeleted) public OperationResourceMetaData(String uniqueId, Api api, Set<Class<? extends ResourceAction>> apiDeleted, boolean noAuthRequired)
{ {
super(uniqueId, RESOURCE_TYPE.OPERATION, null, api, apiDeleted, null, null); super(uniqueId, RESOURCE_TYPE.OPERATION, null, api, apiDeleted, null, null);
this.operationMethod = null; this.operationMethod = null;
this.noAuthRequired = noAuthRequired;
} }
public Method getOperationMethod() public Method getOperationMethod()
@@ -75,6 +80,12 @@ public class OperationResourceMetaData extends ResourceMetadata
return operationMethod; return operationMethod;
} }
@Override
public boolean isNoAuth(Class<? extends ResourceAction> resourceAction)
{
return this.noAuthRequired;
}
@Override @Override
public String toString() public String toString()
{ {
@@ -91,7 +102,8 @@ public class OperationResourceMetaData extends ResourceMetadata
builder.append(this.getOperations()); builder.append(this.getOperations());
builder.append(", apiDeleted="); builder.append(", apiDeleted=");
builder.append(this.getApiDeleted()); builder.append(this.getApiDeleted());
builder.append("operationMethod=").append(operationMethod); builder.append(", operationMethod=").append(operationMethod);
builder.append(", noAuthRequired=").append(noAuthRequired);
builder.append("]"); builder.append("]");
return builder.toString(); return builder.toString();
} }

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Remote API * Alfresco Remote API
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2017 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
@@ -308,7 +308,7 @@ public class ResourceInspector
{ {
if (! (httpMethod.equals(HttpMethod.GET) || httpMethod.equals(HttpMethod.POST))) if (! (httpMethod.equals(HttpMethod.GET) || httpMethod.equals(HttpMethod.POST)))
{ {
throw new IllegalArgumentException("@WebApiNoAuth should only be on GET methods: "+operation.getTitle()+" Or POST method for creating a ticket."); throw new IllegalArgumentException("@WebApiNoAuth should only be on GET or POST methods: " + operation.getTitle());
} }
helper.whenOperationNoAuth(resourceInterfaceWithOneMethod, aMethod); helper.whenOperationNoAuth(resourceInterfaceWithOneMethod, aMethod);
} }
@@ -327,7 +327,7 @@ public class ResourceInspector
Annotation annot = AnnotationUtils.findAnnotation(aMethod, WebApiDescription.class); Annotation annot = AnnotationUtils.findAnnotation(aMethod, WebApiDescription.class);
List<ResourceParameter> parameters = new ArrayList<ResourceParameter>(); List<ResourceParameter> parameters = new ArrayList<ResourceParameter>();
parameters.addAll(inspectParameters(resource, aMethod, httpMethod)); parameters.addAll(inspectParameters(resource, aMethod, httpMethod));
if (annot != null) if (annot != null)
{ {
Map<String, Object> annotAttribs = AnnotationUtils.getAnnotationAttributes(annot); Map<String, Object> annotAttribs = AnnotationUtils.getAnnotationAttributes(annot);
@@ -638,6 +638,7 @@ public class ResourceInspector
* Inspect a resource to find operations on it. * Inspect a resource to find operations on it.
* @param api Api * @param api Api
* @param entityPath String * @param entityPath String
* @param metainfo resource metadata
*/ */
public static void inspectOperations(Api api, Class<?> resource, final String entityPath, List<ResourceMetadata> metainfo) public static void inspectOperations(Api api, Class<?> resource, final String entityPath, List<ResourceMetadata> metainfo)
{ {
@@ -646,13 +647,16 @@ public class ResourceInspector
{ {
for (Entry<String, Pair<ResourceOperation, Method>> opera : operations.entrySet()) for (Entry<String, Pair<ResourceOperation, Method>> opera : operations.entrySet())
{ {
if (isDeleted(opera.getValue().getSecond())) Method annotatedMethod = opera.getValue().getSecond();
final boolean isNoAuthRequired = isNoAuth(annotatedMethod);
if (isDeleted(annotatedMethod))
{ {
metainfo.add(new OperationResourceMetaData(opera.getKey(), api, new HashSet(Arrays.asList(opera.getValue().getFirst())))); metainfo.add(new OperationResourceMetaData(opera.getKey(), api, new HashSet(Arrays.asList(opera.getValue().getFirst())), isNoAuthRequired));
} }
else else
{ {
metainfo.add(new OperationResourceMetaData(opera.getKey(), Arrays.asList(opera.getValue().getFirst()), api, opera.getValue().getSecond())); metainfo.add(new OperationResourceMetaData(opera.getKey(), Arrays.asList(opera.getValue().getFirst()), api, annotatedMethod, isNoAuthRequired));
} }
} }
} }

View File

@@ -1,8 +1,9 @@
/*
/* /*
* #%L * #%L
* Alfresco Remote API * Alfresco Remote API
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2017 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
@@ -86,16 +87,17 @@ public class ResourceMetadata
} }
/** /**
* Indicates if this resource can support the specified HTTPMethod * Gets the data type of the resource parameter
* @param supportedMethod HttpMethod *
* @return true if can support it * @param operation {@code ResourceOperation} object
* @return The data type of the resource parameter
*/ */
@SuppressWarnings("rawtypes")
public Class getObjectType(ResourceOperation operation) public Class getObjectType(ResourceOperation operation)
{ {
for (ResourceParameter param : operation.getParameters()) for (ResourceParameter param : operation.getParameters())
{ {
if (ResourceParameter.KIND.HTTP_BODY_OBJECT.equals(param.getParamType())) { if (ResourceParameter.KIND.HTTP_BODY_OBJECT.equals(param.getParamType()))
{
return param.getDataType(); return param.getDataType();
} }
} }

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Remote API * Alfresco Remote API
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2017 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
@@ -27,6 +27,7 @@ package org.alfresco.rest.framework.tests.api.mocks;
import org.alfresco.rest.framework.Operation; import org.alfresco.rest.framework.Operation;
import org.alfresco.rest.framework.WebApiDescription; import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.WebApiNoAuth;
import org.alfresco.rest.framework.WebApiParam; import org.alfresco.rest.framework.WebApiParam;
import org.alfresco.rest.framework.core.ResourceParameter; import org.alfresco.rest.framework.core.ResourceParameter;
import org.alfresco.rest.framework.resource.EntityResource; import org.alfresco.rest.framework.resource.EntityResource;
@@ -73,4 +74,11 @@ public class GrassEntityResource implements EntityResourceAction.ReadById<Grass>
{ {
//I did a delete //I did a delete
} }
@Operation("cut-noAuth")
@WebApiNoAuth
@WebApiDescription(title = "Cut the grass",successStatus = Status.STATUS_NOT_IMPLEMENTED)
public String cutLawnWithoutAuth(String id, Void notused, Parameters parameters, WithResponse withResponse) {
return "All done without Auth";
}
} }

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Remote API * Alfresco Remote API
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2017 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
@@ -41,7 +41,6 @@ import java.util.Map;
import org.alfresco.rest.api.model.Comment; import org.alfresco.rest.api.model.Comment;
import org.alfresco.rest.api.nodes.NodeCommentsRelation; import org.alfresco.rest.api.nodes.NodeCommentsRelation;
import org.alfresco.rest.api.nodes.NodesEntityResource;
import org.alfresco.rest.framework.Api; import org.alfresco.rest.framework.Api;
import org.alfresco.rest.framework.core.OperationResourceMetaData; import org.alfresco.rest.framework.core.OperationResourceMetaData;
import org.alfresco.rest.framework.core.ResourceInspector; import org.alfresco.rest.framework.core.ResourceInspector;
@@ -76,9 +75,7 @@ import org.alfresco.rest.framework.tests.api.mocks3.GrassEntityResourceNowDelete
import org.alfresco.rest.framework.tests.api.mocks3.SheepBlackSheepResourceIsNoMore; import org.alfresco.rest.framework.tests.api.mocks3.SheepBlackSheepResourceIsNoMore;
import org.alfresco.rest.framework.tests.api.mocks3.SheepEntityResourceWithDeletedMethods; import org.alfresco.rest.framework.tests.api.mocks3.SheepEntityResourceWithDeletedMethods;
import org.alfresco.rest.framework.tests.api.mocks3.SlimGoat; import org.alfresco.rest.framework.tests.api.mocks3.SlimGoat;
import org.alfresco.rest.framework.tools.ApiAssistant;
import org.alfresco.rest.framework.tools.ResponseWriter; import org.alfresco.rest.framework.tools.ResponseWriter;
import org.alfresco.rest.framework.webscripts.ApiWebScript;
import org.alfresco.rest.framework.webscripts.WithResponse; import org.alfresco.rest.framework.webscripts.WithResponse;
import org.alfresco.util.Pair; import org.alfresco.util.Pair;
import org.junit.Test; import org.junit.Test;
@@ -459,7 +456,7 @@ public class InspectorTests
GrassEntityResource grassEntityResource = new GrassEntityResource(); GrassEntityResource grassEntityResource = new GrassEntityResource();
ResourceInspector.inspectOperations(api, GrassEntityResource.class,"-root-", metainfo); ResourceInspector.inspectOperations(api, GrassEntityResource.class,"-root-", metainfo);
assertTrue(metainfo.size()==2); assertEquals(3, metainfo.size());
for (ResourceMetadata resourceMetadata : metainfo) for (ResourceMetadata resourceMetadata : metainfo)
{ {
@@ -480,6 +477,7 @@ public class InspectorTests
Object paramObj = paramType.newInstance(); Object paramObj = paramType.newInstance();
result = (String) ResourceInspectorUtil.invokeMethod(actionMethod,grassEntityResource, "xyz", paramObj, Params.valueOf("notUsed", null, mock(WebScriptRequest.class)), wr); result = (String) ResourceInspectorUtil.invokeMethod(actionMethod,grassEntityResource, "xyz", paramObj, Params.valueOf("notUsed", null, mock(WebScriptRequest.class)), wr);
assertEquals("Growing well",result); assertEquals("Growing well",result);
assertFalse(operationResourceMetaData.isNoAuth(null));
break; break;
case "/-root-/{id}/cut": case "/-root-/{id}/cut":
assertNotNull("GrassEntityResource supports POST", resourceMetadata.getOperation(HttpMethod.POST)); assertNotNull("GrassEntityResource supports POST", resourceMetadata.getOperation(HttpMethod.POST));
@@ -489,6 +487,16 @@ public class InspectorTests
assertEquals("cut should return ACCEPTED", Status.STATUS_NOT_IMPLEMENTED, op.getSuccessStatus()); assertEquals("cut should return ACCEPTED", Status.STATUS_NOT_IMPLEMENTED, op.getSuccessStatus());
result = (String) ResourceInspectorUtil.invokeMethod(actionMethod,grassEntityResource, "xyz", null, Params.valueOf("notUsed", null, mock(WebScriptRequest.class)), wr); result = (String) ResourceInspectorUtil.invokeMethod(actionMethod,grassEntityResource, "xyz", null, Params.valueOf("notUsed", null, mock(WebScriptRequest.class)), wr);
assertEquals("All done",result); assertEquals("All done",result);
assertFalse(operationResourceMetaData.isNoAuth(null));
break;
case "/-root-/{id}/cut-noAuth":
assertNotNull("GrassEntityResource supports POST", resourceMetadata.getOperation(HttpMethod.POST));
op = resourceMetadata.getOperation(HttpMethod.POST);
assertNull(resourceMetadata.getObjectType(op));
assertEquals("cut should return ACCEPTED", Status.STATUS_NOT_IMPLEMENTED, op.getSuccessStatus());
result = (String) ResourceInspectorUtil.invokeMethod(actionMethod,grassEntityResource, "xyz", null, Params.valueOf("notUsed", null, mock(WebScriptRequest.class)), wr);
assertEquals("All done without Auth",result);
assertTrue(operationResourceMetaData.isNoAuth(null));
break; break;
default: default:
fail("Invalid action information."); fail("Invalid action information.");