/**
* PODD is an OWL ontology database used for scientific project management
*
* Copyright (C) 2009-2013 The University Of Queensland
*
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License as published by the Free Software Foundation, either version 3
* 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.podd.resources.test;
import java.io.ByteArrayOutputStream;
import java.io.StringWriter;
import java.util.AbstractMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import org.openrdf.model.Model;
import org.openrdf.model.Resource;
import org.openrdf.model.URI;
import org.openrdf.model.impl.LinkedHashModel;
import org.openrdf.rio.RDFFormat;
import org.openrdf.rio.Rio;
import org.restlet.data.MediaType;
import org.restlet.data.Method;
import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.ClientResource;
import org.restlet.resource.ResourceException;
import com.github.ansell.restletutils.SesameRealmConstants;
import com.github.podd.utils.PODD;
import com.github.podd.utils.PoddRoles;
import com.github.podd.utils.PoddUserStatus;
import com.github.podd.utils.PoddWebConstants;
/**
* Test User Edit Resource at "user/edit/{identifier}"
*
* @author kutila
*
*/
public class UserEditResourceImplTest extends AbstractResourceImplTest
{
/**
* Test display of current user Edit page
*/
@Test
public void testEditCurrentUserHtml() throws Exception
{
final String testIdentifier = "testAdminUser";
final ClientResource userEditClientResource = new ClientResource(this.getUrl(PoddWebConstants.PATH_USER_EDIT));
try
{
userEditClientResource.addQueryParameter(PoddWebConstants.KEY_USER_IDENTIFIER, testIdentifier);
final Representation results =
this.doTestAuthenticatedRequest(userEditClientResource, Method.GET, null, MediaType.TEXT_HTML,
Status.SUCCESS_OK, AbstractResourceImplTest.WITH_ADMIN);
final String body = this.getText(results);
// System.out.println(body);
this.assertFreemarker(body);
Assert.assertTrue("Page missing User identifier", body.contains(testIdentifier));
Assert.assertTrue("Page missing first name", body.contains("Initial Admin"));
Assert.assertTrue("Page missing last name", body.contains("User"));
Assert.assertTrue("Page missing organization", body.contains("Local Organisation"));
Assert.assertTrue("Page missing home page", body.contains("http://www.example.com/testAdmin"));
Assert.assertTrue("Page missing orcid", body.contains("Dummy-ORCID"));
}
finally
{
this.releaseClient(userEditClientResource);
}
}
/**
* Test authenticated edit of current user details
*/
@Test
public void testEditCurrentUserRdf() throws Exception
{
final MediaType mediaType = MediaType.APPLICATION_RDF_XML;
final RDFFormat format = Rio.getWriterFormatForMIMEType(mediaType.getName(), RDFFormat.RDFXML);
final String testIdentifier = "testAdminUser";
// prepare: retrieve Details of existing User
final ClientResource userDetailsClientResource =
new ClientResource(this.getUrl(PoddWebConstants.PATH_USER_DETAILS));
userDetailsClientResource.addQueryParameter(PoddWebConstants.KEY_USER_IDENTIFIER, testIdentifier);
try
{
final Representation results =
this.doTestAuthenticatedRequest(userDetailsClientResource, Method.GET, null, mediaType,
Status.SUCCESS_OK, AbstractResourceImplTest.WITH_ADMIN);
final Model userInfoModel = this.assertRdf(results, format, 11);
// this.log.info("Retrieved [{}] details. ", testIdentifier);
// DebugUtils.printContents(userInfoModel);
// prepare: modify existing User's details
final String modifiedFirstName = "Totally";
final String modifiedLastName = "Newman";
final Resource userUri =
userInfoModel.filter(null, SesameRealmConstants.OAS_USEREMAIL, null).subjects().iterator().next();
userInfoModel.remove(userUri, SesameRealmConstants.OAS_USERFIRSTNAME, null);
userInfoModel.remove(userUri, SesameRealmConstants.OAS_USERLASTNAME, null);
userInfoModel
.add(userUri, SesameRealmConstants.OAS_USERFIRSTNAME, PODD.VF.createLiteral(modifiedFirstName));
userInfoModel.add(userUri, SesameRealmConstants.OAS_USERLASTNAME, PODD.VF.createLiteral(modifiedLastName));
// submit modified details to Edit User Service
final ClientResource userEditClientResource =
new ClientResource(this.getUrl(PoddWebConstants.PATH_USER_EDIT));
try
{
userEditClientResource.addQueryParameter(PoddWebConstants.KEY_USER_IDENTIFIER, testIdentifier);
final ByteArrayOutputStream out = new ByteArrayOutputStream();
Rio.write(userInfoModel, out, format);
final Representation input = new StringRepresentation(out.toString(), mediaType);
final Representation modifiedResults =
this.doTestAuthenticatedRequest(userEditClientResource, Method.POST, input, mediaType,
Status.SUCCESS_OK, AbstractResourceImplTest.WITH_ADMIN);
// verify: response has correct identifier
final Model model = this.assertRdf(modifiedResults, RDFFormat.RDFXML, 1);
Assert.assertEquals("Unexpected user identifier", testIdentifier,
model.filter(null, SesameRealmConstants.OAS_USERIDENTIFIER, null).objectString());
// verify: details have been correctly updated (by retrieving
// User details again)
final ClientResource userDetailsClientResource2 =
new ClientResource(this.getUrl(PoddWebConstants.PATH_USER_DETAILS));
try
{
userDetailsClientResource2.addQueryParameter(PoddWebConstants.KEY_USER_IDENTIFIER, testIdentifier);
final Representation updatedResults =
this.doTestAuthenticatedRequest(userDetailsClientResource2, Method.GET, null, mediaType,
Status.SUCCESS_OK, AbstractResourceImplTest.WITH_ADMIN);
final Model resultsModel = this.assertRdf(updatedResults, format, 11);
Assert.assertEquals("Unexpected user identifier", testIdentifier,
resultsModel.filter(null, SesameRealmConstants.OAS_USERIDENTIFIER, null).objectString());
Assert.assertEquals("Unexpected user URI", userUri.stringValue(),
resultsModel.filter(null, SesameRealmConstants.OAS_USERIDENTIFIER, null).subjects()
.iterator().next().stringValue());
Assert.assertEquals("First name was not modified", modifiedFirstName,
resultsModel.filter(null, SesameRealmConstants.OAS_USERFIRSTNAME, null).objectString());
Assert.assertEquals("Last name was not modified", modifiedLastName,
resultsModel.filter(null, SesameRealmConstants.OAS_USERLASTNAME, null).objectString());
Assert.assertEquals("Role count should not have changed", 1,
resultsModel.filter(null, SesameRealmConstants.OAS_ROLEMAPPEDROLE, null).objects().size());
}
finally
{
this.releaseClient(userDetailsClientResource2);
}
}
finally
{
this.releaseClient(userEditClientResource);
}
}
finally
{
this.releaseClient(userDetailsClientResource);
}
}
/**
* Test display of another user's Edit page as Administrator
*/
@Test
public void testEditOtherUserHtml() throws Exception
{
// prepare: add a Test User account
final String testIdentifier = "testuser@podd.com";
final String testHomePage = "http:///www.john.doe.com";
final List<Map.Entry<URI, URI>> roles = new LinkedList<Map.Entry<URI, URI>>();
roles.add(new AbstractMap.SimpleEntry<URI, URI>(PoddRoles.PROJECT_ADMIN.getURI(), PODD.VF
.createURI("urn:podd:some-project")));
final String testFirstName = "John";
final String testLastName = "Doe";
final String testOrganization = "CSIRO";
final String testOrcid = "john-orcid";
final String testTitle = "Mr";
final String testPhone = "000333434";
final String testAddress = "Some Address";
final String testPosition = "Researcher";
this.loadTestUser(testIdentifier, "testuserpassword", testFirstName, testLastName, testIdentifier,
testHomePage, testOrganization, testOrcid, testTitle, testPhone, testAddress, testPosition, roles,
PoddUserStatus.ACTIVE);
final ClientResource userEditClientResource = new ClientResource(this.getUrl(PoddWebConstants.PATH_USER_EDIT));
try
{
userEditClientResource.addQueryParameter(PoddWebConstants.KEY_USER_IDENTIFIER, testIdentifier);
final Representation results =
this.doTestAuthenticatedRequest(userEditClientResource, Method.GET, null, MediaType.TEXT_HTML,
Status.SUCCESS_OK, AbstractResourceImplTest.WITH_ADMIN);
final String body = this.getText(results);
// System.out.println(body);
this.assertFreemarker(body);
Assert.assertTrue("Page missing User identifier", body.contains(testIdentifier));
Assert.assertTrue("Page missing title", body.contains(testTitle));
Assert.assertTrue("Page missing first name", body.contains(testFirstName));
Assert.assertTrue("Page missing last name", body.contains(testLastName));
Assert.assertTrue("Page missing organization", body.contains(testOrganization));
Assert.assertTrue("Page missing phone", body.contains(testPhone));
Assert.assertTrue("Page missing position", body.contains(testPosition));
Assert.assertTrue("Page missing address", body.contains(testAddress));
Assert.assertTrue("Page missing home page", body.contains(testHomePage));
Assert.assertTrue("Page missing orcid", body.contains(testOrcid));
}
finally
{
this.releaseClient(userEditClientResource);
}
}
/**
* Test authenticated edit of other user details as Administrator
*/
@Test
public void testEditOtherUserRdf() throws Exception
{
final MediaType mediaType = MediaType.APPLICATION_RDF_XML;
final RDFFormat format = Rio.getWriterFormatForMIMEType(mediaType.getName(), RDFFormat.RDFXML);
// prepare: add a Test User account
final String testIdentifier = "testuser@podd.com";
final List<Map.Entry<URI, URI>> roles = new LinkedList<Map.Entry<URI, URI>>();
roles.add(new AbstractMap.SimpleEntry<URI, URI>(PoddRoles.PROJECT_ADMIN.getURI(), PODD.VF
.createURI("urn:podd:some-project")));
this.loadTestUser(testIdentifier, "testuserpassword", "John", "Doe", testIdentifier,
"http:///www.john.doe.com", "CSIRO", "john-orcid", "Mr", "000333434", "Some Address", "Researcher",
roles, PoddUserStatus.ACTIVE);
// prepare: retrieve Details of existing User
final ClientResource userDetailsClientResource =
new ClientResource(this.getUrl(PoddWebConstants.PATH_USER_DETAILS));
try
{
userDetailsClientResource.addQueryParameter(PoddWebConstants.KEY_USER_IDENTIFIER, testIdentifier);
final Representation results =
this.doTestAuthenticatedRequest(userDetailsClientResource, Method.GET, null, mediaType,
Status.SUCCESS_OK, AbstractResourceImplTest.WITH_ADMIN);
final Model userInfoModel = this.assertRdf(results, format, 16);
// this.log.info("Retrieved [{}] details. ", testIdentifier);
// DebugUtils.printContents(userInfoModel);
// prepare: modify existing User's details
final String modifiedFirstName = "Totally";
final String modifiedLastName = "Newman";
final Resource userUri =
userInfoModel.filter(null, SesameRealmConstants.OAS_USEREMAIL, null).subjects().iterator().next();
userInfoModel.remove(userUri, SesameRealmConstants.OAS_USERFIRSTNAME, null);
userInfoModel.remove(userUri, SesameRealmConstants.OAS_USERLASTNAME, null);
userInfoModel.remove(userUri, PODD.PODD_USER_STATUS, null);
userInfoModel
.add(userUri, SesameRealmConstants.OAS_USERFIRSTNAME, PODD.VF.createLiteral(modifiedFirstName));
userInfoModel.add(userUri, SesameRealmConstants.OAS_USERLASTNAME, PODD.VF.createLiteral(modifiedLastName));
userInfoModel.add(userUri, PODD.PODD_USER_STATUS, PoddUserStatus.INACTIVE.getURI());
// submit modified details to Edit User Service
final ClientResource userEditClientResource =
new ClientResource(this.getUrl(PoddWebConstants.PATH_USER_EDIT));
try
{
userEditClientResource.addQueryParameter(PoddWebConstants.KEY_USER_IDENTIFIER, testIdentifier);
final ByteArrayOutputStream out = new ByteArrayOutputStream();
Rio.write(userInfoModel, out, format);
final Representation input = new StringRepresentation(out.toString(), mediaType);
final Representation modifiedResults =
this.doTestAuthenticatedRequest(userEditClientResource, Method.POST, input, mediaType,
Status.SUCCESS_OK, AbstractResourceImplTest.WITH_ADMIN);
// verify: response has correct identifier
final Model model = this.assertRdf(modifiedResults, RDFFormat.RDFXML, 1);
Assert.assertEquals("Unexpected user identifier", testIdentifier,
model.filter(null, SesameRealmConstants.OAS_USERIDENTIFIER, null).objectString());
// verify: details have been correctly updated (by retrieving
// User details again)
final ClientResource userDetailsClientResource2 =
new ClientResource(this.getUrl(PoddWebConstants.PATH_USER_DETAILS));
try
{
userDetailsClientResource2.addQueryParameter(PoddWebConstants.KEY_USER_IDENTIFIER, testIdentifier);
final Representation updatedResults =
this.doTestAuthenticatedRequest(userDetailsClientResource2, Method.GET, null, mediaType,
Status.SUCCESS_OK, AbstractResourceImplTest.WITH_ADMIN);
final Model resultsModel = this.assertRdf(updatedResults, format, 16);
Assert.assertEquals("Unexpected user identifier", testIdentifier,
resultsModel.filter(null, SesameRealmConstants.OAS_USERIDENTIFIER, null).objectString());
Assert.assertEquals("Unexpected user URI", userUri.stringValue(),
resultsModel.filter(null, SesameRealmConstants.OAS_USERIDENTIFIER, null).subjects()
.iterator().next().stringValue());
Assert.assertEquals("First name was not modified", modifiedFirstName,
resultsModel.filter(null, SesameRealmConstants.OAS_USERFIRSTNAME, null).objectString());
Assert.assertEquals("Last name was not modified", modifiedLastName,
resultsModel.filter(null, SesameRealmConstants.OAS_USERLASTNAME, null).objectString());
Assert.assertEquals("Role count should not have changed", 1,
resultsModel.filter(null, SesameRealmConstants.OAS_ROLEMAPPEDROLE, null).objects().size());
Assert.assertEquals("Status was not modified", PoddUserStatus.INACTIVE.getURI(), resultsModel
.filter(null, PODD.PODD_USER_STATUS, null).objectURI());
}
finally
{
this.releaseClient(userDetailsClientResource2);
}
}
finally
{
this.releaseClient(userEditClientResource);
}
}
finally
{
this.releaseClient(userDetailsClientResource);
}
}
/**
* Verify that changing password using the Edit User Interface has no effect
*/
@Test
public void testErrorEditCurrentUserPasswordRdf() throws Exception
{
final String testIdentifier = "testAdminUser";
final String testPassword = "modifiedPassword";
final URI tempUserUri = PODD.VF.createURI("urn:temp:user");
// prepare: create Model with modified password and user identifier
final Model userInfoModel = new LinkedHashModel();
userInfoModel.add(tempUserUri, SesameRealmConstants.OAS_USERIDENTIFIER, PODD.VF.createLiteral(testIdentifier));
userInfoModel.add(tempUserUri, SesameRealmConstants.OAS_USERSECRET, PODD.VF.createLiteral(testPassword));
userInfoModel.add(tempUserUri, PODD.PODD_USER_STATUS, PoddUserStatus.ACTIVE.getURI());
// submit new password to Edit User Service
final MediaType mediaType = MediaType.APPLICATION_RDF_XML;
final RDFFormat format = Rio.getWriterFormatForMIMEType(mediaType.getName(), RDFFormat.RDFXML);
final ClientResource userEditClientResource = new ClientResource(this.getUrl(PoddWebConstants.PATH_USER_EDIT));
try
{
userEditClientResource.addQueryParameter(PoddWebConstants.KEY_USER_IDENTIFIER, testIdentifier);
final ByteArrayOutputStream out = new ByteArrayOutputStream();
Rio.write(userInfoModel, out, format);
final Representation input = new StringRepresentation(out.toString(), mediaType);
final Representation modifiedResults =
this.doTestAuthenticatedRequest(userEditClientResource, Method.POST, input, mediaType,
Status.SUCCESS_OK, AbstractResourceImplTest.WITH_ADMIN);
// verify: response has correct identifier
final Model model = this.assertRdf(modifiedResults, RDFFormat.RDFXML, 1);
Assert.assertEquals("Unexpected user identifier", testIdentifier,
model.filter(null, SesameRealmConstants.OAS_USERIDENTIFIER, null).objectString());
// verify: request with old login details should still succeed
final ClientResource userDetailsClientResource2 =
new ClientResource(this.getUrl(PoddWebConstants.PATH_USER_DETAILS));
try
{
userDetailsClientResource2.addQueryParameter(PoddWebConstants.KEY_USER_IDENTIFIER, testIdentifier);
this.doTestAuthenticatedRequest(userDetailsClientResource2, Method.GET, null, mediaType,
Status.SUCCESS_OK, AbstractResourceImplTest.WITH_ADMIN);
}
catch(final ResourceException e)
{
Assert.fail("Should have succeeded as password was not changed");
}
finally
{
this.releaseClient(userDetailsClientResource2);
}
}
finally
{
this.releaseClient(userEditClientResource);
}
}
/**
* Test error trying to edit a User that does not exist in the system
*/
@Test
public void testErrorEditNonExistentUserRdf() throws Exception
{
final MediaType mediaType = MediaType.APPLICATION_RDF_XML;
final Representation input = new StringRepresentation("Should have user model in JSON", mediaType);
// submit modified details to Edit User Service
final ClientResource userEditClientResource = new ClientResource(this.getUrl(PoddWebConstants.PATH_USER_EDIT));
try
{
userEditClientResource.addQueryParameter(PoddWebConstants.KEY_USER_IDENTIFIER, "noSuchUser");
this.doTestAuthenticatedRequest(userEditClientResource, Method.POST, input, mediaType,
Status.CLIENT_ERROR_BAD_REQUEST, AbstractResourceImplTest.WITH_ADMIN);
Assert.fail("Should have thrown a ResourceException");
}
catch(final ResourceException e)
{
Assert.assertEquals(e.getStatus(), Status.CLIENT_ERROR_BAD_REQUEST);
}
finally
{
this.releaseClient(userEditClientResource);
}
}
/**
* Test error trying to display other user Edit page as non-admin user
*/
@Test
public void testErrorEditOtherUserNonAdminHtml() throws Exception
{
final String testIdentifier = "testAdminUser";
final ClientResource userEditClientResource = new ClientResource(this.getUrl(PoddWebConstants.PATH_USER_EDIT));
try
{
userEditClientResource.addQueryParameter(PoddWebConstants.KEY_USER_IDENTIFIER, testIdentifier);
this.doTestAuthenticatedRequest(userEditClientResource, Method.GET, null, MediaType.TEXT_HTML,
Status.CLIENT_ERROR_UNAUTHORIZED, AbstractResourceImplTest.NO_ADMIN);
Assert.fail("Should have thrown a ResourceException");
}
catch(final ResourceException e)
{
Assert.assertEquals("Expected UNAUTHORIZED error", Status.CLIENT_ERROR_UNAUTHORIZED, e.getStatus());
}
finally
{
this.releaseClient(userEditClientResource);
}
}
/**
* Test error trying to edit other user details as non-admin user
*/
@Test
public void testErrorEditOtherUserNonAdminRdf() throws Exception
{
final MediaType mediaType = MediaType.APPLICATION_RDF_XML;
final RDFFormat format = Rio.getWriterFormatForMIMEType(mediaType.getName(), RDFFormat.RDFXML);
// prepare: add a Test User account
final String testIdentifier = "testuser@podd.com";
final List<Map.Entry<URI, URI>> roles = new LinkedList<Map.Entry<URI, URI>>();
roles.add(new AbstractMap.SimpleEntry<URI, URI>(PoddRoles.PROJECT_ADMIN.getURI(), PODD.VF
.createURI("urn:podd:some-project")));
this.loadTestUser(testIdentifier, "testuserpassword", "John", "Doe", testIdentifier,
"http:///www.john.doe.com", "CSIRO", "john-orcid", "Mr", "000333434", "Some Address", "Researcher",
roles, PoddUserStatus.ACTIVE);
// prepare: retrieve Details of existing User
final ClientResource userDetailsClientResource =
new ClientResource(this.getUrl(PoddWebConstants.PATH_USER_DETAILS));
try
{
userDetailsClientResource.addQueryParameter(PoddWebConstants.KEY_USER_IDENTIFIER, testIdentifier);
final Representation results =
this.doTestAuthenticatedRequest(userDetailsClientResource, Method.GET, null, mediaType,
Status.SUCCESS_OK, AbstractResourceImplTest.WITH_ADMIN);
final Model userInfoModel = this.assertRdf(results, format, 16);
// this.log.info("Retrieved [{}] details. ", testIdentifier);
// DebugUtils.printContents(userInfoModel);
// prepare: modify existing User's details
final String modifiedFirstName = "Totally";
final String modifiedLastName = "Newman";
final Resource userUri =
userInfoModel.filter(null, SesameRealmConstants.OAS_USEREMAIL, null).subjects().iterator().next();
userInfoModel.remove(userUri, SesameRealmConstants.OAS_USERFIRSTNAME, null);
userInfoModel.remove(userUri, SesameRealmConstants.OAS_USERLASTNAME, null);
userInfoModel
.add(userUri, SesameRealmConstants.OAS_USERFIRSTNAME, PODD.VF.createLiteral(modifiedFirstName));
userInfoModel.add(userUri, SesameRealmConstants.OAS_USERLASTNAME, PODD.VF.createLiteral(modifiedLastName));
final StringWriter out = new StringWriter();
Rio.write(userInfoModel, out, format);
final Representation input = new StringRepresentation(out.toString(), mediaType);
// try to submit modified details to Edit User Service
final ClientResource userEditClientResource =
new ClientResource(this.getUrl(PoddWebConstants.PATH_USER_EDIT));
try
{
userEditClientResource.addQueryParameter(PoddWebConstants.KEY_USER_IDENTIFIER, testIdentifier);
this.doTestAuthenticatedRequest(userEditClientResource, Method.POST, input, mediaType,
Status.CLIENT_ERROR_UNAUTHORIZED, AbstractResourceImplTest.NO_ADMIN);
Assert.fail("Should have thrown a ResourceException due to lack of authorization");
}
catch(final ResourceException e)
{
Assert.assertEquals("Should have been Unauthorized", Status.CLIENT_ERROR_UNAUTHORIZED, e.getStatus());
}
finally
{
this.releaseClient(userEditClientResource);
}
}
finally
{
this.releaseClient(userDetailsClientResource);
}
}
}