Web Scripts:

- fix issues integrating with Flex (rename of tunnel url arguments)
- add admin to required authentication levels
- support json callback method (for browser based ajax requests)

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5856 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
David Caruana
2007-06-05 18:17:59 +00:00
parent d28bbd41c5
commit 61b6952524
12 changed files with 95 additions and 21 deletions

View File

@@ -33,6 +33,7 @@ import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.jscript.Node;
import org.alfresco.repo.jscript.ScriptableHashMap;
import org.alfresco.repo.template.TemplateNode;
@@ -132,12 +133,34 @@ public class DeclarativeWebScript extends AbstractWebScript
{
res.setStatus(statusCode);
}
res.setContentType(mimetype + ";charset=UTF-8");
if (logger.isDebugEnabled())
logger.debug("Rendering response: content type=" + mimetype + ", status=" + statusCode);
String callback = req.getJSONCallback();
if (format.equals(WebScriptResponse.JSON_FORMAT) && callback != null)
{
if (logger.isDebugEnabled())
logger.debug("Rendering JSON callback response: content type=" + MimetypeMap.MIMETYPE_TEXT_JAVASCRIPT + ", status=" + statusCode + ", callback=" + callback);
// NOTE: special case for wrapping JSON results in a javascript function callback
res.setContentType(MimetypeMap.MIMETYPE_TEXT_JAVASCRIPT + ";charset=UTF-8");
res.getOutputStream().write((callback + "(").getBytes());
}
else
{
if (logger.isDebugEnabled())
logger.debug("Rendering response: content type=" + mimetype + ", status=" + statusCode);
res.setContentType(mimetype + ";charset=UTF-8");
}
// render response according to requested format
renderFormatTemplate(format, templateModel, res.getWriter());
if (format.equals(WebScriptResponse.JSON_FORMAT) && callback != null)
{
// NOTE: special case for wrapping JSON results in a javascript function callback
res.getOutputStream().write(")".getBytes());
}
}
}
catch(Throwable e)

View File

@@ -259,6 +259,7 @@ public class DeclarativeWebScriptRegistry extends AbstractLifecycleBean
{
// establish static part of url template
boolean wildcard = false;
boolean extension = true;
String uriTemplate = uri.getURI();
int queryArgIdx = uriTemplate.indexOf('?');
if (queryArgIdx != -1)
@@ -278,6 +279,7 @@ public class DeclarativeWebScriptRegistry extends AbstractLifecycleBean
{
uriTemplate = uriTemplate.substring(0, extIdx);
}
extension = false;
}
// index service by static part of url (ensuring no other service has already claimed the url)
@@ -294,7 +296,7 @@ public class DeclarativeWebScriptRegistry extends AbstractLifecycleBean
}
else
{
URLIndex urlIndex = new URLIndex(uriTemplate, wildcard, serviceImpl);
URLIndex urlIndex = new URLIndex(uriTemplate, wildcard, extension, serviceImpl);
webscriptsByURL.put(uriIdx, urlIndex);
if (logger.isDebugEnabled())
@@ -580,13 +582,15 @@ public class DeclarativeWebScriptRegistry extends AbstractLifecycleBean
String matchedPath = null;
DeclarativeWebScriptMatch apiServiceMatch = null;
String match = method.toString().toUpperCase() + ":" + uri;
String matchNoExt = method.toString().toUpperCase() + ":" + ((uri.indexOf('.') != -1) ? uri.substring(0, uri.indexOf('.')) : uri);
// locate full match - on URI and METHOD
for (Map.Entry<String, URLIndex> entry : webscriptsByURL.entrySet())
{
URLIndex urlIndex = entry.getValue();
String index = entry.getKey();
if ((urlIndex.wildcardPath && match.startsWith(index)) || (!urlIndex.wildcardPath && match.equals(index)))
String test = urlIndex.includeExtension ? match : matchNoExt;
if ((urlIndex.wildcardPath && test.startsWith(index)) || (!urlIndex.wildcardPath && test.equals(index)))
{
apiServiceMatch = new DeclarativeWebScriptMatch(urlIndex.path, urlIndex.script);
break;
@@ -715,15 +719,17 @@ public class DeclarativeWebScriptRegistry extends AbstractLifecycleBean
*/
private static class URLIndex
{
private URLIndex(String path, boolean wildcardPath, WebScript script)
private URLIndex(String path, boolean wildcardPath, boolean includeExtension, WebScript script)
{
this.path = path;
this.wildcardPath = wildcardPath;
this.includeExtension = includeExtension;
this.script = script;
}
private String path;
private boolean wildcardPath;
private boolean includeExtension;
private WebScript script;
}

View File

@@ -42,6 +42,7 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.transaction.TransactionUtil;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.web.config.ServerConfigElement;
import org.springframework.context.ApplicationContext;
@@ -62,6 +63,7 @@ public class TestWebScriptServer
// dependencies
protected AuthenticationService authenticationService;
protected TransactionService transactionService;
protected AuthorityService authorityService;
protected DeclarativeWebScriptRegistry registry;
protected ConfigService configService;
@@ -118,7 +120,15 @@ public class TestWebScriptServer
{
this.authenticationService = authenticationService;
}
/**
* @param authorityService
*/
public void setAuthorityService(AuthorityService authorityService)
{
this.authorityService = authorityService;
}
/**
* Sets the Messages resource bundle
*
@@ -200,7 +210,7 @@ public class TestWebScriptServer
MockHttpServletRequest req = createRequest(method, uri);
MockHttpServletResponse res = new MockHttpServletResponse();
WebScriptRuntime runtime = new WebScriptServletRuntime(registry, transactionService, null, req, res, serverConfig);
WebScriptRuntime runtime = new WebScriptServletRuntime(registry, transactionService, authorityService, null, req, res, serverConfig);
runtime.executeScript();
return res;
@@ -225,7 +235,7 @@ public class TestWebScriptServer
}
MockHttpServletResponse res = new MockHttpServletResponse();
WebScriptRuntime runtime = new WebScriptServletRuntime(registry, transactionService, null, req, res, serverConfig);
WebScriptRuntime runtime = new WebScriptServletRuntime(registry, transactionService, authorityService, null, req, res, serverConfig);
runtime.executeScript();
return res;

View File

@@ -42,7 +42,8 @@ public interface WebScriptDescription
{
none,
guest,
user
user,
admin
}
/**

View File

@@ -140,6 +140,13 @@ public interface WebScriptRequest
* @return format style (excludes any)
*/
public FormatStyle getFormatStyle();
/**
* Get the JSON callback method
*
* @return method (or null, if not specified)
*/
public String getJSONCallback();
/**
* Get User Agent

View File

@@ -138,5 +138,13 @@ public abstract class WebScriptRequestImpl implements WebScriptRequest
}
}
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScriptRequest#getJSONCallback()
*/
public String getJSONCallback()
{
return getParameter("alf_callback");
}
}

View File

@@ -28,13 +28,13 @@ import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.TransactionUtil;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication;
import org.alfresco.web.scripts.WebScriptDescription.RequiredTransaction;
@@ -62,6 +62,7 @@ public abstract class WebScriptRuntime
/** Component Dependencies */
private WebScriptRegistry registry;
private TransactionService transactionService;
private AuthorityService authorityService;
/**
* Construct
@@ -69,10 +70,11 @@ public abstract class WebScriptRuntime
* @param registry web script registry
* @param transactionService transaction service
*/
public WebScriptRuntime(WebScriptRegistry registry, TransactionService transactionService)
public WebScriptRuntime(WebScriptRegistry registry, TransactionService transactionService, AuthorityService authorityService)
{
this.registry = registry;
this.transactionService = transactionService;
this.authorityService = authorityService;
}
/**
@@ -265,7 +267,7 @@ public abstract class WebScriptRuntime
{
wrappedExecute(scriptReq, scriptRes);
}
else if (required == RequiredAuthentication.user && isGuest)
else if ((required == RequiredAuthentication.user || required == RequiredAuthentication.admin) && isGuest)
{
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires user authentication; however, a guest has attempted access.");
}
@@ -291,6 +293,11 @@ public abstract class WebScriptRuntime
//
if (authenticate(required, isGuest))
{
if (required == RequiredAuthentication.admin && !authorityService.hasAdminAuthority())
{
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires admin authentication; however, a non-admin has attempted access.");
}
// Execute Web Script
wrappedExecute(scriptReq, scriptRes);
}

View File

@@ -33,6 +33,7 @@ import javax.servlet.http.HttpServletResponse;
import org.alfresco.config.Config;
import org.alfresco.config.ConfigService;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.web.config.ServerConfigElement;
import org.apache.commons.logging.Log;
@@ -56,6 +57,7 @@ public class WebScriptServlet extends HttpServlet
// Component Dependencies
private DeclarativeWebScriptRegistry registry;
private TransactionService transactionService;
private AuthorityService authorityService;
private WebScriptServletAuthenticator authenticator;
protected ConfigService configService;
@@ -70,6 +72,7 @@ public class WebScriptServlet extends HttpServlet
ApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
registry = (DeclarativeWebScriptRegistry)context.getBean("webscripts.registry");
transactionService = (TransactionService)context.getBean("transactionComponent");
authorityService = (AuthorityService)context.getBean("authorityServce");
configService = (ConfigService)context.getBean("webClientConfigService");
// retrieve authenticator via servlet initialisation parameter
@@ -105,7 +108,7 @@ public class WebScriptServlet extends HttpServlet
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Pragma", "no-cache");
WebScriptRuntime runtime = new WebScriptServletRuntime(registry, transactionService, authenticator, req, res, serverConfig);
WebScriptRuntime runtime = new WebScriptServletRuntime(registry, transactionService, authorityService, authenticator, req, res, serverConfig);
runtime.executeScript();
}

View File

@@ -27,6 +27,7 @@ package org.alfresco.web.scripts;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.web.config.ServerConfigElement;
import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication;
@@ -54,10 +55,11 @@ public class WebScriptServletRuntime extends WebScriptRuntime
* @param req
* @param res
*/
public WebScriptServletRuntime(WebScriptRegistry registry, TransactionService transactionService, WebScriptServletAuthenticator authenticator,
public WebScriptServletRuntime(WebScriptRegistry registry, TransactionService transactionService,
AuthorityService authorityService, WebScriptServletAuthenticator authenticator,
HttpServletRequest req, HttpServletResponse res, ServerConfigElement serverConfig)
{
super(registry, transactionService);
super(registry, transactionService, authorityService);
this.req = req;
this.res = res;
this.authenticator = authenticator;
@@ -78,13 +80,13 @@ public class WebScriptServletRuntime extends WebScriptRuntime
String overload = req.getHeader("X-HTTP-Method-Override");
if (overload == null || overload.length() == 0)
{
overload = req.getParameter("alf:method");
overload = req.getParameter("alf_method");
overloadParam = true;
}
if (overload != null && overload.length() > 0)
{
if (logger.isDebugEnabled())
logger.debug("POST is tunnelling method '" + overload + "' as specified by " + (overloadParam ? "alf:method parameter" : "X-HTTP-Method-Override header"));
logger.debug("POST is tunnelling method '" + overload + "' as specified by " + (overloadParam ? "alf_method parameter" : "X-HTTP-Method-Override header"));
method = overload;
}

View File

@@ -37,6 +37,7 @@ import javax.faces.event.ActionEvent;
import javax.faces.event.FacesEvent;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.web.scripts.DeclarativeWebScriptRegistry;
import org.alfresco.web.scripts.WebScriptMatch;
@@ -70,6 +71,7 @@ public class UIWebScript extends SelfRenderingComponent
private WebScriptRegistry registry;
private TransactionService txnService;
private AuthorityService authorityService;
/**
* Default constructor
@@ -80,6 +82,7 @@ public class UIWebScript extends SelfRenderingComponent
FacesContext.getCurrentInstance());
this.registry = (DeclarativeWebScriptRegistry)ctx.getBean("webscripts.registry");
this.txnService = (TransactionService)ctx.getBean("transactionComponent");
this.authorityService = (AuthorityService)ctx.getBean("authorityService");
}
/**
@@ -225,7 +228,7 @@ public class UIWebScript extends SelfRenderingComponent
WebScriptJSFRuntime(FacesContext fc, String scriptUrl)
{
super(registry, txnService);
super(registry, txnService, authorityService);
this.fc = fc;
this.scriptUrl = scriptUrl;
this.script = WebScriptURLRequest.splitURL(scriptUrl)[2];

View File

@@ -39,6 +39,7 @@ import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.WindowState;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.web.scripts.DeclarativeWebScriptRegistry;
import org.alfresco.web.scripts.WebScript;
@@ -73,6 +74,7 @@ public class WebScriptPortlet implements Portlet
// Component Dependencies
protected DeclarativeWebScriptRegistry registry;
protected TransactionService transactionService;
protected AuthorityService authorityService;
protected WebScriptPortletAuthenticator authenticator;
@@ -86,6 +88,7 @@ public class WebScriptPortlet implements Portlet
WebApplicationContext ctx = (WebApplicationContext)portletCtx.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
registry = (DeclarativeWebScriptRegistry)ctx.getBean("webscripts.registry");
transactionService = (TransactionService)ctx.getBean("transactionComponent");
authorityService = (AuthorityService)ctx.getBean("authorityService");
authenticator = (WebScriptPortletAuthenticator)ctx.getBean("webscripts.authenticator.jsr168");
}
@@ -209,7 +212,7 @@ public class WebScriptPortlet implements Portlet
*/
public WebScriptPortalRuntime(RenderRequest req, RenderResponse res, String requestUrl)
{
super(registry, transactionService);
super(registry, transactionService, authorityService);
this.req = req;
this.res = res;
this.requestUrlParts = WebScriptURLRequest.splitURL(requestUrl);