Enhanced User properties available ready for User Profile component - added new properties to content model definition, ContentModel constants file and Slingshot User objects.

Added AlfrescoUser object, to be responsible for persisting changes to User Profile.
Added concept of ThreadLocalRequestContext - similar to FacesContext in that it has a static accessor method to retrieve the "current" instance.
Removal of 'alfresco-system' endpoint from web-framework and replaced usage with 'alfresco' endpoint:
 - removes the need for admin user detailed to be stored in web-framework config files (!) and being constantly transmitted between tiers
 - refactored appropriate webscripts to accept non-admin authentication but added code checks to ensure non-admin users can only bring back meta-data about themselves
 - refactored AVMRemoteStore and RemoteStore client to use authenticated endpoint rather than system admin authentication driven endpoint
 - this also reduces the the traffic between tiers and vastly reduces the number of login tickets requested
Added open HTTP endpoint - for use by RSS feed components etc. that point to any website feed - configured as 'unsecure' endpoint so purposely cannot be accessed via proxy URLs.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@9920 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Kevin Roast
2008-07-17 14:38:55 +00:00
parent 5f5937479b
commit 773b9e811e
7 changed files with 156 additions and 119 deletions

View File

@@ -2,6 +2,6 @@
<shortname>Remote AVM Store</shortname> <shortname>Remote AVM Store</shortname>
<description>Remote service mirroring the Store interface - to an AVM store</description> <description>Remote service mirroring the Store interface - to an AVM store</description>
<url>/remotestore/{method}/{path}</url> <url>/remotestore/{method}/{path}</url>
<authentication>admin</authentication> <authentication>user</authentication>
<format default="">argument</format> <format default="">argument</format>
</webscript> </webscript>

View File

@@ -3,6 +3,6 @@
<description>Remote service mirroring the Store interface - to an AVM store</description> <description>Remote service mirroring the Store interface - to an AVM store</description>
<url>/remotestore/{method}</url> <url>/remotestore/{method}</url>
<url>/remotestore/{method}/{path}</url> <url>/remotestore/{method}/{path}</url>
<authentication>admin</authentication> <authentication>none</authentication>
<format default="">argument</format> <format default="">argument</format>
</webscript> </webscript>

View File

@@ -2,6 +2,6 @@
<shortname>Remote AVM Store</shortname> <shortname>Remote AVM Store</shortname>
<description>Remote service mirroring the Store interface - to an AVM store</description> <description>Remote service mirroring the Store interface - to an AVM store</description>
<url>/remotestore/{method}/{path}</url> <url>/remotestore/{method}/{path}</url>
<authentication>admin</authentication> <authentication>user</authentication>
<format default="">argument</format> <format default="">argument</format>
</webscript> </webscript>

View File

@@ -3,6 +3,6 @@
<description>Content Metadata Retrieval Service</description> <description>Content Metadata Retrieval Service</description>
<url>/webframework/content/metadata</url> <url>/webframework/content/metadata</url>
<format default="html">argument</format> <format default="html">argument</format>
<authentication>admin</authentication> <authentication>user</authentication>
<transaction>required</transaction> <transaction>required</transaction>
</webscript> </webscript>

View File

@@ -55,11 +55,9 @@
<#assign renderable = false> <#assign renderable = false>
<#if val?is_string == true> <#if val?is_string == true>
<#assign renderable = true> <#assign renderable = true>
</#if> <#elseif val?is_date == true>
<#if val?is_date == true>
<#assign renderable = true> <#assign renderable = true>
</#if> <#elseif val?is_boolean == true>
<#if val?is_boolean == true>
<#assign renderable = true> <#assign renderable = true>
</#if> </#if>
<#if renderable == true> <#if renderable == true>
@@ -67,12 +65,10 @@
, ,
</#if> </#if>
<#if val?is_string == true> <#if val?is_string == true>
"${key}" : "${val}" "${key}" : "${val?js_string}"
</#if> <#elseif val?is_date == true>
<#if val?is_date == true>
"${key}" : "${val?datetime}" "${key}" : "${val?datetime}"
</#if> <#elseif val?is_boolean == true>
<#if val?is_boolean == true>
"${key}" : "${val}" "${key}" : "${val}"
</#if> </#if>
<#assign first = false> <#assign first = false>

View File

@@ -7,21 +7,28 @@ if(args["id"] != null)
object = search.findNode(id); object = search.findNode(id);
} }
// if not by id, then allow for user id // if not by id, then allow for user id - but only if current user is the user!
if(object == null && args["user"] != null) else if(args["user"] != null)
{ {
var userId = args["user"]; var userId = args["user"];
object = people.getPerson(userId); if (userId == person.properties.userName)
{
object = person;
}
} }
// load content by relative path // load content by relative path
if(object == null) else
{ {
var path = args["path"]; var path = args["path"];
if(path == null || path == "" || path == "/") if(path == null || path == "" || path == "/")
{
path = "/Company Home"; path = "/Company Home";
}
else else
{
path = "/Company Home" + path; path = "/Company Home" + path;
}
// look up the content by path // look up the content by path
object = roothome.childByNamePath(path); object = roothome.childByNamePath(path);

View File

@@ -32,6 +32,8 @@ import java.util.SortedMap;
import org.alfresco.repo.avm.AVMNodeConverter; import org.alfresco.repo.avm.AVMNodeConverter;
import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.service.cmr.avm.AVMExistsException; import org.alfresco.service.cmr.avm.AVMExistsException;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor; import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
@@ -104,77 +106,85 @@ public class AVMRemoteStore extends BaseRemoteStore
* @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#getDocument(org.alfresco.web.scripts.WebScriptResponse, java.lang.String) * @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#getDocument(org.alfresco.web.scripts.WebScriptResponse, java.lang.String)
*/ */
@Override @Override
protected void getDocument(WebScriptResponse res, String path) throws IOException protected void getDocument(final WebScriptResponse res, final String path) throws IOException
{ {
String avmPath = buildAVMPath(path); final String avmPath = buildAVMPath(path);
AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath); final AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath);
if (desc == null) if (desc == null)
{ {
res.setStatus(Status.STATUS_NOT_FOUND); res.setStatus(Status.STATUS_NOT_FOUND);
return; return;
} }
ContentReader reader; AuthenticationUtil.runAs(new RunAsWork<Object>()
try
{ {
reader = this.avmService.getContentReader(-1, avmPath); @SuppressWarnings("synthetic-access")
public Object doWork() throws Exception
if (reader == null)
{ {
throw new WebScriptException("No content found for AVM file: " + avmPath); ContentReader reader;
} try
// establish mimetype
String mimetype = reader.getMimetype();
if (mimetype == null || mimetype.length() == 0)
{
mimetype = MimetypeMap.MIMETYPE_BINARY;
int extIndex = path.lastIndexOf('.');
if (extIndex != -1)
{ {
String ext = path.substring(extIndex + 1); reader = avmService.getContentReader(-1, avmPath);
String mt = this.mimetypeService.getMimetypesByExtension().get(ext);
if (mt != null) if (reader == null)
{ {
mimetype = mt; throw new WebScriptException("No content found for AVM file: " + avmPath);
}
// establish mimetype
String mimetype = reader.getMimetype();
if (mimetype == null || mimetype.length() == 0)
{
mimetype = MimetypeMap.MIMETYPE_BINARY;
int extIndex = path.lastIndexOf('.');
if (extIndex != -1)
{
String ext = path.substring(extIndex + 1);
String mt = mimetypeService.getMimetypesByExtension().get(ext);
if (mt != null)
{
mimetype = mt;
}
}
}
// set mimetype for the content and the character encoding + length for the stream
WebScriptServletResponse httpRes = (WebScriptServletResponse)res;
httpRes.setContentType(mimetype);
httpRes.getHttpServletResponse().setCharacterEncoding(reader.getEncoding());
httpRes.getHttpServletResponse().setDateHeader("Last-Modified", desc.getModDate());
httpRes.setHeader("Content-Length", Long.toString(reader.getSize()));
// get the content and stream directly to the response output stream
// assuming the repository is capable of streaming in chunks, this should allow large files
// to be streamed directly to the browser response stream.
try
{
reader.getContent(res.getOutputStream());
}
catch (SocketException e1)
{
// the client cut the connection - our mission was accomplished apart from a little error message
if (logger.isInfoEnabled())
logger.info("Client aborted stream read:\n\tnode: " + avmPath + "\n\tcontent: " + reader);
}
catch (ContentIOException e2)
{
if (logger.isInfoEnabled())
logger.info("Client aborted stream read:\n\tnode: " + avmPath + "\n\tcontent: " + reader);
} }
} }
catch (AccessDeniedException ae)
{
res.setStatus(Status.STATUS_UNAUTHORIZED);
}
catch (AVMNotFoundException avmErr)
{
res.setStatus(Status.STATUS_NOT_FOUND);
}
return null;
} }
}, AuthenticationUtil.getSystemUserName());
// set mimetype for the content and the character encoding + length for the stream
WebScriptServletResponse httpRes = (WebScriptServletResponse)res;
httpRes.setContentType(mimetype);
httpRes.getHttpServletResponse().setCharacterEncoding(reader.getEncoding());
httpRes.getHttpServletResponse().setDateHeader("Last-Modified", desc.getModDate());
httpRes.setHeader("Content-Length", Long.toString(reader.getSize()));
// get the content and stream directly to the response output stream
// assuming the repository is capable of streaming in chunks, this should allow large files
// to be streamed directly to the browser response stream.
try
{
reader.getContent(res.getOutputStream());
}
catch (SocketException e1)
{
// the client cut the connection - our mission was accomplished apart from a little error message
if (logger.isInfoEnabled())
logger.info("Client aborted stream read:\n\tnode: " + avmPath + "\n\tcontent: " + reader);
}
catch (ContentIOException e2)
{
if (logger.isInfoEnabled())
logger.info("Client aborted stream read:\n\tnode: " + avmPath + "\n\tcontent: " + reader);
}
}
catch (AccessDeniedException ae)
{
res.setStatus(Status.STATUS_UNAUTHORIZED);
}
catch (AVMNotFoundException avmErr)
{
res.setStatus(Status.STATUS_NOT_FOUND);
}
} }
/* (non-Javadoc) /* (non-Javadoc)
@@ -195,45 +205,53 @@ public class AVMRemoteStore extends BaseRemoteStore
* @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#createDocument(org.alfresco.web.scripts.WebScriptResponse, java.lang.String, java.io.InputStream) * @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#createDocument(org.alfresco.web.scripts.WebScriptResponse, java.lang.String, java.io.InputStream)
*/ */
@Override @Override
protected void createDocument(WebScriptResponse res, String path, InputStream content) protected void createDocument(final WebScriptResponse res, final String path, final InputStream content)
{ {
String avmPath = buildAVMPath(path); AuthenticationUtil.runAs(new RunAsWork<Object>()
try
{ {
String[] parts = AVMNodeConverter.SplitBase(avmPath); @SuppressWarnings("synthetic-access")
String[] dirs = parts[0].split("/"); public Object doWork() throws Exception
String parentPath = dirs[0] + "/" + dirs[1];
int index = 2;
while (index < dirs.length)
{ {
String dirPath = parentPath + "/" + dirs[index]; String avmPath = buildAVMPath(path);
if (this.avmService.lookup(-1, dirPath) == null) try
{ {
this.avmService.createDirectory(parentPath, dirs[index]); String[] parts = AVMNodeConverter.SplitBase(avmPath);
String[] dirs = parts[0].split("/");
String parentPath = dirs[0] + "/" + dirs[1];
int index = 2;
while (index < dirs.length)
{
String dirPath = parentPath + "/" + dirs[index];
if (avmService.lookup(-1, dirPath) == null)
{
avmService.createDirectory(parentPath, dirs[index]);
}
parentPath = dirPath;
index++;
}
avmService.createFile(parts[0], parts[1], content);
} }
parentPath = dirPath; catch (AccessDeniedException ae)
index++; {
res.setStatus(Status.STATUS_UNAUTHORIZED);
}
catch (AVMExistsException avmErr)
{
res.setStatus(Status.STATUS_CONFLICT);
}
return null;
} }
}, AuthenticationUtil.getSystemUserName());
this.avmService.createFile(parts[0], parts[1], content);
}
catch (AccessDeniedException ae)
{
res.setStatus(Status.STATUS_UNAUTHORIZED);
}
catch (AVMExistsException avmErr)
{
res.setStatus(Status.STATUS_CONFLICT);
}
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#updateDocument(org.alfresco.web.scripts.WebScriptResponse, java.lang.String, java.io.InputStream) * @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#updateDocument(org.alfresco.web.scripts.WebScriptResponse, java.lang.String, java.io.InputStream)
*/ */
@Override @Override
protected void updateDocument(WebScriptResponse res, String path, InputStream content) protected void updateDocument(final WebScriptResponse res, final String path, final InputStream content)
{ {
String avmPath = buildAVMPath(path); final String avmPath = buildAVMPath(path);
AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath); AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath);
if (desc == null) if (desc == null)
{ {
@@ -241,24 +259,32 @@ public class AVMRemoteStore extends BaseRemoteStore
return; return;
} }
try AuthenticationUtil.runAs(new RunAsWork<Object>()
{ {
ContentWriter writer = this.avmService.getContentWriter(avmPath); @SuppressWarnings("synthetic-access")
writer.putContent(content); public Object doWork() throws Exception
} {
catch (AccessDeniedException ae) try
{ {
res.setStatus(Status.STATUS_UNAUTHORIZED); ContentWriter writer = avmService.getContentWriter(avmPath);
} writer.putContent(content);
}
catch (AccessDeniedException ae)
{
res.setStatus(Status.STATUS_UNAUTHORIZED);
}
return null;
}
}, AuthenticationUtil.getSystemUserName());
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#deleteDocument(org.alfresco.web.scripts.WebScriptResponse, java.lang.String) * @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#deleteDocument(org.alfresco.web.scripts.WebScriptResponse, java.lang.String)
*/ */
@Override @Override
protected void deleteDocument(WebScriptResponse res, String path) protected void deleteDocument(final WebScriptResponse res, final String path)
{ {
String avmPath = buildAVMPath(path); final String avmPath = buildAVMPath(path);
AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath); AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath);
if (desc == null) if (desc == null)
{ {
@@ -266,14 +292,22 @@ public class AVMRemoteStore extends BaseRemoteStore
return; return;
} }
try AuthenticationUtil.runAs(new RunAsWork<Object>()
{ {
this.avmService.removeNode(avmPath); @SuppressWarnings("synthetic-access")
} public Object doWork() throws Exception
catch (AccessDeniedException ae) {
{ try
res.setStatus(Status.STATUS_UNAUTHORIZED); {
} avmService.removeNode(avmPath);
}
catch (AccessDeniedException ae)
{
res.setStatus(Status.STATUS_UNAUTHORIZED);
}
return null;
}
}, AuthenticationUtil.getSystemUserName());
} }
/* (non-Javadoc) /* (non-Javadoc)