use of org.springframework.extensions.webscripts.Description in project records-management by Alfresco.
the class BaseWebScriptUnitTest method getMockedDescription.
/**
* Helper method to get mocked description class
*
* @return {@link DescriptionExtension} mocked description class
*/
protected Description getMockedDescription() {
Description mockedDescription = mock(Description.class);
doReturn(mock(RequiredCache.class)).when(mockedDescription).getRequiredCache();
return mockedDescription;
}
use of org.springframework.extensions.webscripts.Description in project alfresco-remote-api by Alfresco.
the class RepositoryContainer method executeScriptInternal.
protected void executeScriptInternal(WebScriptRequest scriptReq, WebScriptResponse scriptRes, final Authenticator auth) throws IOException {
final WebScript script = scriptReq.getServiceMatch().getWebScript();
final Description desc = script.getDescription();
final boolean debug = logger.isDebugEnabled();
// Escalate the webscript declared level of authentication to the container required authentication
// eg. must be guest if MT is enabled unless credentials are empty
RequiredAuthentication containerRequiredAuthentication = getRequiredAuthentication();
final RequiredAuthentication required = (desc.getRequiredAuthentication().compareTo(containerRequiredAuthentication) < 0 && !auth.emptyCredentials() ? containerRequiredAuthentication : desc.getRequiredAuthentication());
final boolean isGuest = scriptReq.isGuest();
if (required == RequiredAuthentication.none) {
// TODO revisit - cleared here, in-lieu of WebClient clear
// AuthenticationUtil.clearCurrentSecurityContext();
transactionedExecuteAs(script, scriptReq, scriptRes);
} 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.");
} else {
try {
AuthenticationUtil.pushAuthentication();
//
if (debug) {
String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
logger.debug("Current authentication: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser));
logger.debug("Authentication required: " + required);
logger.debug("Guest login requested: " + isGuest);
}
//
// Apply appropriate authentication to Web Script invocation
//
RetryingTransactionCallback<Boolean> authWork = new RetryingTransactionCallback<Boolean>() {
public Boolean execute() throws Exception {
if (auth == null || auth.authenticate(required, isGuest)) {
// Check to see if they supplied HTTP Auth or Ticket as guest, on a script that needs more
if (required == RequiredAuthentication.user || required == RequiredAuthentication.admin) {
String authenticatedUser = AuthenticationUtil.getFullyAuthenticatedUser();
String runAsUser = AuthenticationUtil.getRunAsUser();
if ((authenticatedUser == null) || (authenticatedUser.equals(runAsUser) && authorityService.hasGuestAuthority()) || (!authenticatedUser.equals(runAsUser) && authorityService.isGuestAuthority(authenticatedUser))) {
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires user authentication; however, a guest has attempted access.");
}
}
// Check to see if they're admin or system on an Admin only script
if (required == RequiredAuthentication.admin && !(authorityService.hasAdminAuthority() || AuthenticationUtil.getFullyAuthenticatedUser().equals(AuthenticationUtil.getSystemUserName()))) {
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires admin authentication; however, a non-admin has attempted access.");
}
if (debug) {
String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
logger.debug("Authentication: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser));
}
return true;
}
return false;
}
};
boolean readOnly = transactionService.isReadOnly();
boolean requiresNew = !readOnly && AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_READ_ONLY;
if (transactionService.getRetryingTransactionHelper().doInTransaction(authWork, readOnly, requiresNew)) {
// Execute Web Script if authentication passed
// The Web Script has its own txn management with potential runAs() user
transactionedExecuteAs(script, scriptReq, scriptRes);
} else {
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Authentication failed for Web Script " + desc.getId());
}
} finally {
//
// Reset authentication for current thread
//
AuthenticationUtil.popAuthentication();
if (debug) {
String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
logger.debug("Authentication reset: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser));
}
}
}
}
use of org.springframework.extensions.webscripts.Description in project alfresco-remote-api by Alfresco.
the class RepositoryContainer method transactionedExecute.
/**
* Execute script within required level of transaction
*
* @param script WebScript
* @param scriptReq WebScriptRequest
* @param scriptRes WebScriptResponse
* @throws IOException
*/
protected void transactionedExecute(final WebScript script, final WebScriptRequest scriptReq, final WebScriptResponse scriptRes) throws IOException {
try {
final Description description = script.getDescription();
if (description.getRequiredTransaction() == RequiredTransaction.none) {
script.execute(scriptReq, scriptRes);
} else {
final BufferedRequest bufferedReq;
final BufferedResponse bufferedRes;
RequiredTransactionParameters trxParams = description.getRequiredTransactionParameters();
if (trxParams.getCapability() == TransactionCapability.readwrite) {
if (trxParams.getBufferSize() > 0) {
if (logger.isDebugEnabled())
logger.debug("Creating Transactional Response for ReadWrite transaction; buffersize=" + trxParams.getBufferSize());
// create buffered request and response that allow transaction retrying
bufferedReq = new BufferedRequest(scriptReq, streamFactory);
bufferedRes = new BufferedResponse(scriptRes, trxParams.getBufferSize());
} else {
if (logger.isDebugEnabled())
logger.debug("Transactional Response bypassed for ReadWrite - buffersize=0");
bufferedReq = null;
bufferedRes = null;
}
} else {
bufferedReq = null;
bufferedRes = null;
}
// encapsulate script within transaction
RetryingTransactionCallback<Object> work = new RetryingTransactionCallback<Object>() {
public Object execute() throws Exception {
try {
if (logger.isDebugEnabled())
logger.debug("Begin retry transaction block: " + description.getRequiredTransaction() + "," + description.getRequiredTransactionParameters().getCapability());
if (bufferedRes == null) {
script.execute(scriptReq, scriptRes);
} else {
// Reset the request and response in case of a transaction retry
bufferedReq.reset();
bufferedRes.reset();
script.execute(bufferedReq, bufferedRes);
}
} catch (Exception e) {
if (logger.isDebugEnabled()) {
logger.debug("Transaction exception: " + description.getRequiredTransaction() + ": " + e.getMessage());
// Note: user transaction shouldn't be null, but just in case inside this exception handler
UserTransaction userTrx = RetryingTransactionHelper.getActiveUserTransaction();
if (userTrx != null) {
logger.debug("Transaction status: " + userTrx.getStatus());
}
}
UserTransaction userTrx = RetryingTransactionHelper.getActiveUserTransaction();
if (userTrx != null) {
if (userTrx.getStatus() != Status.STATUS_MARKED_ROLLBACK) {
if (logger.isDebugEnabled())
logger.debug("Marking web script transaction for rollback");
try {
userTrx.setRollbackOnly();
} catch (Throwable re) {
if (logger.isDebugEnabled())
logger.debug("Caught and ignoring exception during marking for rollback: " + re.getMessage());
}
}
}
// re-throw original exception for retry
throw e;
} finally {
if (logger.isDebugEnabled())
logger.debug("End retry transaction block: " + description.getRequiredTransaction() + "," + description.getRequiredTransactionParameters().getCapability());
}
return null;
}
};
boolean readonly = description.getRequiredTransactionParameters().getCapability() == TransactionCapability.readonly;
boolean requiresNew = description.getRequiredTransaction() == RequiredTransaction.requiresnew;
// NOT have any side effects so this scenario as a warning sign something maybe amiss, see ALF-10179.
if (logger.isDebugEnabled() && !readonly && "GET".equalsIgnoreCase(description.getMethod())) {
logger.debug("Webscript with URL '" + scriptReq.getURL() + "' is a GET request but it's descriptor has declared a readwrite transaction is required");
}
try {
RetryingTransactionHelper transactionHelper = transactionService.getRetryingTransactionHelper();
if (script instanceof LoginPost) {
// login script requires read-write transaction because of authorization intercepter
transactionHelper.setForceWritable(true);
}
transactionHelper.doInTransaction(work, readonly, requiresNew);
} catch (TooBusyException e) {
// Map TooBusyException to a 503 status code
throw new WebScriptException(HttpServletResponse.SC_SERVICE_UNAVAILABLE, e.getMessage(), e);
} finally {
// Get rid of any temporary files
if (bufferedReq != null) {
bufferedReq.close();
}
}
// Ensure a response is always flushed after successful execution
if (bufferedRes != null) {
bufferedRes.writeResponse();
}
}
} catch (IOException ioe) {
Throwable socketException = ExceptionStackUtil.getCause(ioe, SocketException.class);
Class<?> clientAbortException = null;
try {
clientAbortException = Class.forName("org.apache.catalina.connector.ClientAbortException");
} catch (ClassNotFoundException e) {
// do nothing
}
// Note: if you need to look for more exceptions in the stack, then create a static array and pass it in
if ((socketException != null && socketException.getMessage().contains("Broken pipe")) || (clientAbortException != null && ExceptionStackUtil.getCause(ioe, clientAbortException) != null)) {
if (logger.isDebugEnabled()) {
logger.warn("Client has cut off communication", ioe);
} else {
logger.info("Client has cut off communication");
}
} else {
throw ioe;
}
}
}
use of org.springframework.extensions.webscripts.Description in project alfresco-remote-api by Alfresco.
the class XssVulnerabilityTest method testXssVulnerability.
public void testXssVulnerability() throws Throwable {
webscriptsRegistry.reset();
final int scriptsSize = webscriptsRegistry.getWebScripts().size();
int i = 0, successCount = 0, wserrcount = 0, vulnCount = 0;
LinkedList<String> vulnerabileURLS = new LinkedList<String>();
for (WebScript ws : webscriptsRegistry.getWebScripts()) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("progress: " + ++i + "/" + scriptsSize);
}
Description wsDesc = ws.getDescription();
if (SKIP_WEBSCRIPT_CHECK_ID_SET.contains(wsDesc.getId())) {
// skip
continue;
}
boolean isMethodCheck = METHODS_TO_CHECK_SET.contains(wsDesc.getMethod());
boolean isFormatCheck = FORMATS_TO_CHECK_SET.contains(wsDesc.getDefaultFormat());
if (isMethodCheck && isFormatCheck) {
for (String malArg : MALICIOUS_ARGS) {
String[] uris = wsDesc.getURIs();
for (String uri : uris) {
if (isUriSkip(uri)) {
continue;
}
// always parse url because we cannot rely on getArguments():
// - sometimes getArguments() returns null although URI has arguments
// - sometimes getArguments() returns set of args that does not contain args from url
List<String> parsedArgs = parseArgsFromURI(uri);
if (0 == parsedArgs.size()) {
// no arguments in uri, skip
continue;
}
String url = substituteMaliciousArgInURI(uri, parsedArgs, malArg);
Response resp;
try {
resp = sendRequest(createRequest(wsDesc.getMethod(), url), -1);
} catch (WebScriptException e) {
// skip webscript errors
++wserrcount;
continue;
}
String respString = resp.getContentAsString();
if (resp.getStatus() == Status.STATUS_OK) {
++successCount;
}
// do case insensitive check because argument can be converted to lowercase on page
if (respString.toLowerCase().contains(malArg.toLowerCase())) {
vulnerabileURLS.add(wsDesc.getMethod() + " " + url);
vulnCount++;
}
}
}
}
}
if (getLogger().isDebugEnabled()) {
getLogger().debug("OK html responses count: " + successCount);
getLogger().debug("Webscript errors count: " + wserrcount);
getLogger().debug("Vulnerabile URLs count: " + vulnCount);
}
for (String url : vulnerabileURLS) {
getLogger().warn("Vulnerabile URL: " + url);
}
assertTrue("Vulnerabile URLs found: " + vulnerabileURLS, vulnerabileURLS.size() == 0);
}
use of org.springframework.extensions.webscripts.Description in project records-management by Alfresco.
the class BaseWebScriptUnitTest method getMockedContainer.
/**
* Helper method to get mocked container object.
*
* @param template classpath location of webscripts ftl template
* @return {@link Container} mocked container
*/
protected Container getMockedContainer(String template) throws Exception {
FormatRegistry mockedFormatRegistry = mock(FormatRegistry.class);
doReturn("application/json").when(mockedFormatRegistry).getMimeType(anyString(), anyString());
ScriptProcessorRegistry mockedScriptProcessorRegistry = mock(ScriptProcessorRegistry.class);
doReturn(null).when(mockedScriptProcessorRegistry).findValidScriptPath(anyString());
TemplateProcessorRegistry mockedTemplateProcessorRegistry = mock(TemplateProcessorRegistry.class);
doReturn(template).when(mockedTemplateProcessorRegistry).findValidTemplatePath(anyString());
FTLTemplateProcessor ftlTemplateProcessor = new FTLTemplateProcessor() {
@Override
protected TemplateLoader getTemplateLoader() {
return new ClassTemplateLoader(getClass(), "/");
}
};
ftlTemplateProcessor.init();
doReturn(ftlTemplateProcessor).when(mockedTemplateProcessorRegistry).getTemplateProcessor(anyString());
Container mockedContainer = mock(Container.class);
doReturn(mockedFormatRegistry).when(mockedContainer).getFormatRegistry();
doReturn(mockedScriptProcessorRegistry).when(mockedContainer).getScriptProcessorRegistry();
doReturn(mockedTemplateProcessorRegistry).when(mockedContainer).getTemplateProcessorRegistry();
Map<String, Object> containerTemplateParameters = new HashMap<>(5);
containerTemplateParameters.put("jsonUtils", new JSONUtils());
containerTemplateParameters.put("people", getMockedPeopleObject());
doReturn(containerTemplateParameters).when(mockedContainer).getTemplateParameters();
SearchPath mockedSearchPath = mock(SearchPath.class);
doReturn(false).when(mockedSearchPath).hasDocument(anyString());
doReturn(mockedSearchPath).when(mockedContainer).getSearchPath();
// setup description
Description mockDescription = mock(Description.class);
doReturn(mock(RequiredCache.class)).when(mockDescription).getRequiredCache();
return mockedContainer;
}
Aggregations