diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/login.get.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/login.get.json.ftl
new file mode 100644
index 0000000000..d023f4aec5
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/login.get.json.ftl
@@ -0,0 +1,6 @@
+{
+ data:
+ {
+ ticket:${ticket}
+ }
+}
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/login.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/login.post.desc.xml
new file mode 100644
index 0000000000..b8a043b985
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/login.post.desc.xml
@@ -0,0 +1,24 @@
+
+ Login (POST)
+
+
+ Input
+
+ JSON Data Object.
+
+ - username
- cleartext username
+ - password
- cleartext password
+
+
+ Returns the new authentication ticket.
+ ]]>
+
+ /api/login
+
+ none
+ required
+ public_api
+ Authentication
+
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/login.post.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/login.post.json.ftl
new file mode 100644
index 0000000000..d023f4aec5
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/login.post.json.ftl
@@ -0,0 +1,6 @@
+{
+ data:
+ {
+ ticket:${ticket}
+ }
+}
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/login.post.xml.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/login.post.xml.ftl
new file mode 100644
index 0000000000..d311e170fd
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/login.post.xml.ftl
@@ -0,0 +1,2 @@
+
+${ticket}
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/loginticket.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/loginticket.get.desc.xml
index bf949010e5..86e47b1be8 100644
--- a/config/alfresco/templates/webscripts/org/alfresco/repository/loginticket.get.desc.xml
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/loginticket.get.desc.xml
@@ -1,13 +1,16 @@
Validate Login Ticket
- The ticket may be invalid, or expired, or the user may have been locked out.
+ The ticket may be invalid, or expired, or the user may have been locked out.
+
+ For security reasons this script will not validate the ticket of another user.
- - If the ticket is valid retuns 200, STATUS_SUCCESS
- - If the ticket is not valid returns a 404, STATUS_NOT_FOUND
+ - If the ticket is valid retuns, STATUS_SUCCESS (200)
+ - If the ticket is not valid return, STATUS_NOT_FOUND (404)
+ - If the ticket does not belong to the current user, STATUS_NOT_FOUND (404)
]]>
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/tagging/node.tags.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/tagging/node.tags.post.desc.xml
index 315c4f02bf..884e6f06ce 100644
--- a/config/alfresco/templates/webscripts/org/alfresco/repository/tagging/node.tags.post.desc.xml
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/tagging/node.tags.post.desc.xml
@@ -2,7 +2,8 @@
Add tag
Input: array of String
+
Input:
+
(mandatory) array of String
Returns the array of tags
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/upload/upload.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/upload/upload.post.desc.xml
index cca092796a..a7cb44b82e 100644
--- a/config/alfresco/templates/webscripts/org/alfresco/repository/upload/upload.post.desc.xml
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/upload/upload.post.desc.xml
@@ -1,12 +1,12 @@
File Upload
HTML form data
- - filedata
+ - filedata, (mandatory) HTML type file
- siteid
- containerid
- uploaddirectory
diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml
index b21140a780..f9fa0b832d 100644
--- a/config/alfresco/web-scripts-application-context.xml
+++ b/config/alfresco/web-scripts-application-context.xml
@@ -190,6 +190,11 @@
+
+
+
+
+
diff --git a/source/java/org/alfresco/repo/web/scripts/LoginTest.java b/source/java/org/alfresco/repo/web/scripts/LoginTest.java
new file mode 100644
index 0000000000..6ac7a2616c
--- /dev/null
+++ b/source/java/org/alfresco/repo/web/scripts/LoginTest.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2005-2008 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.web.scripts;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.repo.security.authentication.AuthenticationComponent;
+import org.alfresco.service.cmr.security.AuthenticationService;
+import org.alfresco.service.cmr.security.PersonService;
+import org.alfresco.util.PropertyMap;
+import org.alfresco.web.scripts.Status;
+import org.alfresco.web.scripts.TestWebScriptServer.GetRequest;
+import org.alfresco.web.scripts.TestWebScriptServer.DeleteRequest;
+import org.alfresco.web.scripts.TestWebScriptServer.PostRequest;
+import org.alfresco.web.scripts.TestWebScriptServer.Response;
+import org.json.JSONObject;
+
+/**
+ * Junit test for login / logout and validate web scripts
+ *
+ * testing uri /api/login
+ */
+public class LoginTest extends BaseWebScriptTest
+{
+ private AuthenticationService authenticationService;
+ private AuthenticationComponent authenticationComponent;
+ private PersonService personService;
+
+ private static final String USER_ONE = "AuthenticationTestOne";
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ this.authenticationService = (AuthenticationService)getServer().getApplicationContext().getBean("AuthenticationService");
+ this.authenticationComponent = (AuthenticationComponent)getServer().getApplicationContext().getBean("authenticationComponent");
+ this.personService = (PersonService)getServer().getApplicationContext().getBean("PersonService");
+
+ this.authenticationComponent.setSystemUserAsCurrentUser();
+ createUser(USER_ONE, USER_ONE);
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ }
+
+ private void createUser(String userName, String password)
+ {
+ if (this.authenticationService.authenticationExists(userName) == false)
+ {
+ this.authenticationService.createAuthentication(userName, password.toCharArray());
+
+ PropertyMap ppOne = new PropertyMap(4);
+ ppOne.put(ContentModel.PROP_USERNAME, userName);
+ ppOne.put(ContentModel.PROP_FIRSTNAME, "firstName");
+ ppOne.put(ContentModel.PROP_LASTNAME, "lastName");
+ ppOne.put(ContentModel.PROP_EMAIL, "email@email.com");
+ ppOne.put(ContentModel.PROP_JOBTITLE, "jobTitle");
+
+ this.personService.createPerson(ppOne);
+ }
+ }
+
+ private String parseTicket(String ticketResult)
+ {
+ int startTag = ticketResult.indexOf("");
+ int endTag = ticketResult.indexOf("");
+ if ((startTag != -1) && (endTag != -1))
+ {
+ return ticketResult.substring(startTag+("".length()), endTag);
+ }
+ return "";
+ }
+
+ /**
+ * Positive test - login and retrieve a ticket via get - return xml,
+ * - via get method
+ * validate ticket
+ * logout
+ * fail to validate ticket
+ * fail to get ticket
+ */
+ public void testAuthentication() throws Exception
+ {
+ /**
+ * Login via get method to return xml
+ */
+ String loginURL = "/api/login?u=" + USER_ONE + "&pw=" + USER_ONE;
+ Response resp = sendRequest(new GetRequest(loginURL), Status.STATUS_OK);
+ String xmlFragment = resp.getContentAsString();
+
+ assertNotNull("xmlFragment");
+ assertTrue("xmlFragment contains ticket", xmlFragment.contains(""));
+ String ticket = parseTicket(xmlFragment);
+
+ String ticketURL = "/api/login/ticket/"+ticket;
+
+ /**
+ * Negative test - validate as "admin" - should fail with a 404
+ */
+ setDefaultRunAs("admin");
+ sendRequest(new GetRequest(ticketURL), Status.STATUS_NOT_FOUND);
+
+ /**
+ * Validate the ticket - should succeed
+ */
+ setDefaultRunAs(USER_ONE);
+
+ sendRequest(new GetRequest(ticketURL), Status.STATUS_OK);
+
+ /**
+ * Logout
+ */
+ sendRequest(new DeleteRequest(ticketURL), Status.STATUS_OK);
+
+ /**
+ * Validate the ticket - should fail now
+ */
+ sendRequest(new GetRequest(ticketURL), Status.STATUS_NOT_FOUND);
+
+ }
+
+ /**
+ * Positive test - login and retrieve a ticket,
+ * - via json method
+ */
+ public void testAuthenticationGetJSON() throws Exception
+ {
+ /**
+ * Login via get method to return json
+ */
+ String loginURL = "/api/login.json?u=" + USER_ONE + "&pw=" + USER_ONE ;
+ Response resp = sendRequest(new GetRequest(loginURL), Status.STATUS_OK);
+ JSONObject result = new JSONObject(resp.getContentAsString());
+ JSONObject data = result.getJSONObject("data");
+ String ticket = data.getString("ticket");
+ assertNotNull("ticket is null", ticket);
+
+ /**
+ * This is now testing the framework ... With a different format.
+ */
+ String login2URL = "/api/login?u=" + USER_ONE + "&pw=" + USER_ONE + "&format=json";
+ Response resp2 = sendRequest(new GetRequest(login2URL), Status.STATUS_OK);
+ JSONObject result2 = new JSONObject(resp2.getContentAsString());
+ JSONObject data2 = result2.getJSONObject("data");
+ String ticket2 = data2.getString("ticket");
+ assertNotNull("ticket is null", ticket2);
+
+ }
+
+ /**
+ * Authenticate via a POST
+ * @throws Exception
+ */
+ public void testPostLogin() throws Exception
+ {
+ String loginURL = "/api/login";
+ /**
+ * logon via POST and JSON
+ */
+ {
+ JSONObject req = new JSONObject();
+ req.put("username", USER_ONE);
+ req.put("password", USER_ONE);
+ Response response = sendRequest(new PostRequest(loginURL, req.toString(), "application/json"), Status.STATUS_OK);
+
+ JSONObject result = new JSONObject(response.getContentAsString());
+ JSONObject data = result.getJSONObject("data");
+ String ticket = data.getString("ticket");
+ assertNotNull("ticket null", ticket);
+ }
+
+ /**
+ * Negative test - wrong password
+ */
+ {
+ JSONObject req = new JSONObject();
+ req.put("username", USER_ONE);
+ req.put("password", "blurb");
+ sendRequest(new PostRequest(loginURL, req.toString(), "application/json"), Status.STATUS_FORBIDDEN);
+ }
+ /**
+ * Negative test - missing username
+ */
+ {
+ JSONObject req = new JSONObject();
+ req.put("password", USER_ONE);
+ sendRequest(new PostRequest(loginURL, req.toString(), "application/json"), Status.STATUS_BAD_REQUEST);
+ }
+
+ /**
+ * Negative test - missing password
+ */
+ {
+ JSONObject req = new JSONObject();
+ req.put("username", USER_ONE);
+ sendRequest(new PostRequest(loginURL, req.toString(), "application/json"), Status.STATUS_BAD_REQUEST);
+ }
+ }
+
+
+ /**
+ * Negative tests - wrong password
+ */
+ public void testWrongPassword() throws Exception
+ {
+ /**
+ * Login via get method and wrong password, should get FORBIDDEN
+ */
+ String loginURL = "/api/login?u=" + USER_ONE + "&pw=" + "crap";
+ sendRequest(new GetRequest(loginURL), Status.STATUS_FORBIDDEN);
+ }
+
+ /**
+ * Negative test - missing parameters
+ */
+ public void testMissingParameters() throws Exception
+ {
+ /**
+ * Login via get method missing pw
+ */
+ String loginURL = "/api/login?u=" + USER_ONE;
+ sendRequest(new GetRequest(loginURL), Status.STATUS_BAD_REQUEST);
+
+ /**
+ * Login via get method missing u
+ */
+ String login2URL = "/api/login?&pw=" + USER_ONE;
+ sendRequest(new GetRequest(login2URL), Status.STATUS_BAD_REQUEST);
+
+ }
+}
diff --git a/source/java/org/alfresco/repo/web/scripts/bean/AbstractLoginBean.java b/source/java/org/alfresco/repo/web/scripts/bean/AbstractLoginBean.java
new file mode 100644
index 0000000000..11d063c069
--- /dev/null
+++ b/source/java/org/alfresco/repo/web/scripts/bean/AbstractLoginBean.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.web.scripts.bean;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.alfresco.repo.security.authentication.AuthenticationException;
+import org.alfresco.service.cmr.security.AuthenticationService;
+import org.alfresco.web.scripts.DeclarativeWebScript;
+import org.alfresco.web.scripts.Status;
+import org.alfresco.web.scripts.WebScriptException;
+import org.alfresco.web.scripts.WebScriptRequest;
+
+
+/**
+ * common code between Get based login and POST based login
+ */
+/* package scope */ abstract class AbstractLoginBean extends DeclarativeWebScript
+{
+ // dependencies
+ private AuthenticationService authenticationService;
+
+ /**
+ * @param authenticationService
+ */
+ public void setAuthenticationService(AuthenticationService authenticationService)
+ {
+ this.authenticationService = authenticationService;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
+ */
+ @Override
+ protected Map executeImpl(WebScriptRequest req, Status status)
+ {
+ return null;
+ }
+
+ protected Map login(String username, String password)
+ {
+
+ try
+ {
+ // get ticket
+ authenticationService.authenticate(username, password.toCharArray());
+
+ // add ticket to model for javascript and template access
+ Map model = new HashMap(7, 1.0f);
+ model.put("ticket", authenticationService.getCurrentTicket());
+ return model;
+ }
+ catch(AuthenticationException e)
+ {
+ throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "Login failed");
+ }
+ finally
+ {
+ authenticationService.clearCurrentSecurityContext();
+ }
+ }
+}
diff --git a/source/java/org/alfresco/repo/web/scripts/bean/Login.java b/source/java/org/alfresco/repo/web/scripts/bean/Login.java
index 3bf64e03ca..e4ab427ee4 100644
--- a/source/java/org/alfresco/repo/web/scripts/bean/Login.java
+++ b/source/java/org/alfresco/repo/web/scripts/bean/Login.java
@@ -42,24 +42,11 @@ import org.alfresco.web.scripts.WebScriptRequest;
*
* @author davidc
*/
-public class Login extends DeclarativeWebScript
-{
- // dependencies
- private AuthenticationService authenticationService;
-
- /**
- * @param authenticationService
- */
- public void setAuthenticationService(AuthenticationService authenticationService)
- {
- this.authenticationService = authenticationService;
- }
-
-
+public class Login extends AbstractLoginBean
+{
/* (non-Javadoc)
* @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
*/
- @Override
protected Map executeImpl(WebScriptRequest req, Status status)
{
// extract username and password
@@ -74,24 +61,7 @@ public class Login extends DeclarativeWebScript
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Password not specified");
}
- try
- {
- // get ticket
- authenticationService.authenticate(username, password.toCharArray());
-
- // add ticket to model for javascript and template access
- Map model = new HashMap(7, 1.0f);
- model.put("ticket", authenticationService.getCurrentTicket());
- return model;
- }
- catch(AuthenticationException e)
- {
- throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "Login failed");
- }
- finally
- {
- authenticationService.clearCurrentSecurityContext();
- }
+ return login(username, password);
}
}
diff --git a/source/java/org/alfresco/repo/web/scripts/bean/LoginPost.java b/source/java/org/alfresco/repo/web/scripts/bean/LoginPost.java
new file mode 100644
index 0000000000..f6fe863061
--- /dev/null
+++ b/source/java/org/alfresco/repo/web/scripts/bean/LoginPost.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2005-2009 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.web.scripts.bean;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.alfresco.repo.security.authentication.AuthenticationException;
+import org.alfresco.util.Content;
+import org.alfresco.web.scripts.Status;
+import org.alfresco.web.scripts.WebScriptException;
+import org.alfresco.web.scripts.WebScriptRequest;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+
+/**
+ * Post based login script
+ *
+ */
+public class LoginPost extends AbstractLoginBean
+{
+
+ /* (non-Javadoc)
+ * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
+ */
+ protected Map executeImpl(WebScriptRequest req, Status status)
+ {
+ // Extract user and password from JSON POST
+ Content c = req.getContent();
+ if (c == null)
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST,
+ "Missing POST body.");
+ }
+ // TODO accept xml type.
+
+ // extract username and password from JSON object
+ JSONObject json;
+ try {
+ json = new JSONObject(c.getContent());
+ String username = json.getString("username");
+ String password = json.getString("password");
+
+ if (username == null || username.length() == 0)
+ {
+ throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Username not specified");
+ }
+
+ if (password == null)
+ {
+ throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Password not specified");
+ }
+
+ return login(username, password);
+ }
+ catch (JSONException jErr)
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST,
+ "Unable to parse JSON POST body: " + jErr.getMessage());
+ }
+ catch (IOException ioErr)
+ {
+ throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR,
+ "Unable to retrieve POST body: " + ioErr.getMessage());
+ }
+ }
+}
diff --git a/source/java/org/alfresco/repo/web/scripts/bean/LoginTicket.java b/source/java/org/alfresco/repo/web/scripts/bean/LoginTicket.java
index 1f3ca789ae..458d62d289 100644
--- a/source/java/org/alfresco/repo/web/scripts/bean/LoginTicket.java
+++ b/source/java/org/alfresco/repo/web/scripts/bean/LoginTicket.java
@@ -77,9 +77,12 @@ public class LoginTicket extends DeclarativeWebScript
try
{
String ticketUser = ticketComponent.validateTicket(ticket);
+
+ String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
- // do not go any further if tickets are different
- if (!AuthenticationUtil.getFullyAuthenticatedUser().equals(ticketUser))
+ // do not go any further if tickets are different
+ // or the user is not fully authenticated
+ if (currentUser == null || !currentUser.equals(ticketUser))
{
status.setRedirect(true);
status.setCode(HttpServletResponse.SC_NOT_FOUND);