Refactor Contacts Sample to use new ACL security.

This commit is contained in:
Ben Alex 2004-11-15 03:25:39 +00:00
parent bc9a599bf7
commit 6e687d47d4
39 changed files with 1788 additions and 1044 deletions

View File

@ -2,6 +2,7 @@ Changes in version 0.7 (2004-xx-xx)
-----------------------------------
* Major CVS repository restructure to support Maven and eliminate libraries
* Major improvements to Contacts sample application (now demos ACL security)
* Added AspectJ support (especially useful for instance-level security)
* Added MethodDefinitionSourceAdvisor for performance and autoproxying
* Added MethodDefinitionMap querying of interfaces defined by secure objects
@ -11,7 +12,8 @@ Changes in version 0.7 (2004-xx-xx)
* Improved BasicAclProvider to only respond to specified ACL object requests
* Refactored MethodDefinitionSource to work with Method, not MethodInvocation
* Refactored AbstractSecurityInterceptor to better support other AOP libraries
* Fixed AbstractProcessingFitler to use removeAttribute (JRun compatibility)
* Fixed AbstractProcessingFilter to use removeAttribute (JRun compatibility)
* Fixed GrantedAuthorityEffectiveAclResolver support of UserDetails principals
* Moved MethodSecurityInterceptor to ...intercept.method.aopalliance package
* Documentation improvements

View File

@ -0,0 +1,59 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import net.sf.acegisecurity.acl.basic.SimpleAclEntry;
/**
* Model object for add permission use case.
*
* @author Ben Alex
* @version $Id$
*/
public class AddPermission {
//~ Instance fields ========================================================
public Contact contact;
public Integer permission = new Integer(SimpleAclEntry.NOTHING);
public String recipient;
//~ Methods ================================================================
public void setContact(Contact contact) {
this.contact = contact;
}
public Contact getContact() {
return contact;
}
public void setPermission(Integer permission) {
this.permission = permission;
}
public Integer getPermission() {
return permission;
}
public void setRecipient(String recipient) {
this.recipient = recipient;
}
public String getRecipient() {
return recipient;
}
}

View File

@ -0,0 +1,162 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import net.sf.acegisecurity.acl.basic.SimpleAclEntry;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.RequestUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
import org.springframework.web.servlet.view.RedirectView;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Controller for adding an ACL permission.
*
* @author Ben Alex
* @version $Id$
*/
public class AddPermissionController extends SimpleFormController
implements InitializingBean {
//~ Instance fields ========================================================
private ContactManager contactManager;
//~ Methods ================================================================
public void setContactManager(ContactManager contact) {
this.contactManager = contact;
}
public ContactManager getContactManager() {
return contactManager;
}
public void afterPropertiesSet() throws Exception {
if (contactManager == null) {
throw new IllegalArgumentException(
"A ContactManager implementation is required");
}
}
protected ModelAndView disallowDuplicateFormSubmission(
HttpServletRequest request, HttpServletResponse response)
throws Exception {
BindException errors = new BindException(formBackingObject(request),
getCommandName());
errors.reject("err.duplicateFormSubmission",
"Duplicate form submission.");
return showForm(request, response, errors);
}
protected Object formBackingObject(HttpServletRequest request)
throws Exception {
int contactId = RequestUtils.getRequiredIntParameter(request,
"contactId");
Contact contact = contactManager.getById(new Integer(contactId));
AddPermission addPermission = new AddPermission();
addPermission.setContact(contact);
return addPermission;
}
protected ModelAndView handleInvalidSubmit(HttpServletRequest request,
HttpServletResponse response) throws Exception {
return disallowDuplicateFormSubmission(request, response);
}
protected ModelAndView onSubmit(HttpServletRequest request,
HttpServletResponse response, Object command, BindException errors)
throws Exception {
AddPermission addPermission = (AddPermission) command;
try {
contactManager.addPermission(addPermission.getContact(),
addPermission.getRecipient(), addPermission.getPermission());
} catch (DataAccessException existingPermission) {
existingPermission.printStackTrace();
errors.rejectValue("recipient", "err.recipientExistsForContact",
"This recipient already has permissions to this contact.");
return showForm(request, response, errors);
}
return new ModelAndView(new RedirectView(getSuccessView()));
}
protected Map referenceData(HttpServletRequest request)
throws Exception {
Map model = new HashMap();
model.put("recipients", listRecipients(request));
model.put("permissions", listPermissions(request));
return model;
}
private Map listPermissions(HttpServletRequest request) {
Map map = new LinkedHashMap();
map.put(new Integer(SimpleAclEntry.NOTHING),
getApplicationContext().getMessage("select.none", null, "None",
request.getLocale()));
map.put(new Integer(SimpleAclEntry.ADMINISTRATION),
getApplicationContext().getMessage("select.administer", null,
"Administer", request.getLocale()));
map.put(new Integer(SimpleAclEntry.READ),
getApplicationContext().getMessage("select.read", null, "Read",
request.getLocale()));
map.put(new Integer(SimpleAclEntry.DELETE),
getApplicationContext().getMessage("select.delete", null, "Delete",
request.getLocale()));
map.put(new Integer(SimpleAclEntry.READ_WRITE_DELETE),
getApplicationContext().getMessage("select.readWriteDelete", null,
"Read+Write+Delete", request.getLocale()));
return map;
}
private Map listRecipients(HttpServletRequest request) {
Map map = new LinkedHashMap();
map.put("",
getApplicationContext().getMessage("select.pleaseSelect", null,
"-- please select --", request.getLocale()));
Iterator recipientsIter = contactManager.getAllRecipients().iterator();
while (recipientsIter.hasNext()) {
String recipient = (String) recipientsIter.next();
map.put(recipient, recipient);
}
return map;
}
}

View File

@ -0,0 +1,66 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import net.sf.acegisecurity.acl.basic.SimpleAclEntry;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
/**
* Validates {@link AddPermission}.
*
* @author Ben Alex
* @version $Id$
*/
public class AddPermissionValidator implements Validator {
//~ Methods ================================================================
public boolean supports(Class clazz) {
return clazz.equals(AddPermission.class);
}
public void validate(Object obj, Errors errors) {
AddPermission addPermission = (AddPermission) obj;
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "permission",
"err.permission", "Permission is required");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "recipient",
"err.recipient", "Recipient is required");
if (addPermission.getPermission() != null) {
int permission = addPermission.getPermission().intValue();
if ((permission != SimpleAclEntry.NOTHING)
&& (permission != SimpleAclEntry.ADMINISTRATION)
&& (permission != SimpleAclEntry.READ)
&& (permission != SimpleAclEntry.DELETE)
&& (permission != SimpleAclEntry.READ_WRITE_DELETE)) {
errors.rejectValue("permission", "err.permission.invalid",
"The indicated permission is invalid.");
}
}
if (addPermission.getRecipient() != null) {
if (addPermission.getRecipient().length() > 100) {
errors.rejectValue("recipient", "err.recipient.length",
"The recipient is too long (maximum 100 characters).");
}
}
}
}

View File

@ -0,0 +1,92 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import net.sf.acegisecurity.acl.AclEntry;
import net.sf.acegisecurity.acl.AclManager;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.bind.RequestUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Controller for "administer" index page.
*
* @author Ben Alex
* @version $Id$
*/
public class AdminPermissionController implements Controller, InitializingBean {
//~ Instance fields ========================================================
private AclManager aclManager;
private ContactManager contactManager;
//~ Methods ================================================================
public void setAclManager(AclManager aclManager) {
this.aclManager = aclManager;
}
public AclManager getAclManager() {
return aclManager;
}
public void setContactManager(ContactManager contact) {
this.contactManager = contact;
}
public ContactManager getContactManager() {
return contactManager;
}
public void afterPropertiesSet() throws Exception {
if (contactManager == null) {
throw new IllegalArgumentException(
"A ContactManager implementation is required");
}
if (aclManager == null) {
throw new IllegalArgumentException(
"An aclManager implementation is required");
}
}
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
int id = RequestUtils.getRequiredIntParameter(request, "contactId");
Contact contact = contactManager.getById(new Integer(id));
AclEntry[] acls = aclManager.getAcls(contact);
Map model = new HashMap();
model.put("contact", contact);
model.put("acls", acls);
return new ModelAndView("adminPermission", "model", model);
}
}

View File

@ -25,12 +25,13 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Demonstrates accessing the {@link ContactManager} via remoting protocols.
*
*
* <P>
* Based on Spring's JPetStore sample, written by Juergen Hoeller.
* </p>
@ -92,32 +93,34 @@ public class ClientApplication {
System.out.println("Found; Trying to setPassword(String) to "
+ password);
} catch (NoSuchMethodException ignored) {}
catch (IllegalAccessException ignored) {}
catch (InvocationTargetException ignored) {}
catch (IllegalAccessException ignored) {}
catch (InvocationTargetException ignored) {}
stopWatch.start(beanName);
Contact[] contacts = null;
List contacts = null;
for (int i = 0; i < nrOfCalls; i++) {
contacts = remoteContactManager.getAllByOwner(forOwner);
contacts = remoteContactManager.getAll();
}
stopWatch.stop();
if (contacts.length != 0) {
for (int i = 0; i < contacts.length; i++) {
System.out.println("Contact " + i + ": "
+ contacts[i].toString());
if (contacts.size() == 0) {
Iterator listIterator = contacts.iterator();
while (listIterator.hasNext()) {
Contact contact = (Contact) listIterator.next();
System.out.println("Contact: " + contact.toString());
}
} else {
System.out.println("No contacts found belonging to owner");
System.out.println(
"No contacts found which this user has permission to");
}
System.out.println();
System.out.println(stopWatch.prettyPrint());
}
System.out.println(stopWatch.prettyPrint());
}
public static void main(String[] args) {

View File

@ -17,10 +17,6 @@ package sample.contact;
/**
* Represents a contact.
*
* <P>
* <code>id</code> and <code>owner</code> are immutable.
* </p>
*
* @author Ben Alex
* @version $Id$
@ -31,20 +27,15 @@ public class Contact {
private Integer id;
private String email;
private String name;
private String owner;
//~ Constructors ===========================================================
public Contact(Integer id, String name, String email, String owner) {
this.id = id;
public Contact(String name, String email) {
this.name = name;
this.email = email;
this.owner = owner;
}
private Contact() {
super();
}
public Contact() {}
//~ Methods ================================================================
@ -66,6 +57,10 @@ public class Contact {
return email;
}
public void setId(Integer id) {
this.id = id;
}
/**
* DOCUMENT ME!
*
@ -93,22 +88,12 @@ public class Contact {
return name;
}
/**
* DOCUMENT ME!
*
* @return Returns the owner.
*/
public String getOwner() {
return owner;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(super.toString() + ": ");
sb.append("Id: " + this.getId() + "; ");
sb.append("Name: " + this.getName() + "; ");
sb.append("Email: " + this.getEmail() + "; ");
sb.append("Owner: " + this.getOwner());
sb.append("Email: " + this.getEmail());
return sb.toString();
}

View File

@ -0,0 +1,75 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import java.util.List;
/**
* Provides access to the application's persistence layer.
*
* @author Ben Alex
* @version $Id$
*/
public interface ContactDao {
//~ Methods ================================================================
public Contact getById(Integer id);
public void create(Contact contact);
/**
* Creates an acl_object_identity for the specified Contact.
*
* @param contact to create an entry for
*
* @return the acl_object_identity identifier
*/
public Integer createAclObjectIdentity(Contact contact);
/**
* Given an acl_object_identitiy identifier, grant the specified recipient
* read access to the object identified.
*
* @param aclObjectIdentity to assign the read permission against
* @param recipient receiving the permission
* @param permission to assign
*/
public void createPermission(Integer aclObjectIdentity, String recipient,
int permission);
public void delete(Integer contactId);
public void deletePermission(Integer aclObjectIdentity, String recipient);
public List findAll();
public List findAllPrincipals();
public List findAllRoles();
/**
* Obtains the acl_object_identity for the specified Contact.
*
* @param contact to locate an acl_object_identity for
*
* @return the acl_object_identity identifier or <code>null</code> if not
* found
*/
public Integer lookupAclObjectIdentity(Contact contact);
public void update(Contact contact);
}

View File

@ -0,0 +1,309 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import net.sf.acegisecurity.acl.basic.SimpleAclEntry;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.jdbc.object.MappingSqlQuery;
import org.springframework.jdbc.object.SqlUpdate;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.List;
import javax.sql.DataSource;
/**
* Base implementation of {@link ContactDao} that uses Spring JDBC services.
*
* @author Ben Alex
* @version $Id$
*/
public class ContactDaoSpring extends JdbcDaoSupport implements ContactDao {
//~ Instance fields ========================================================
private AclObjectIdentityByObjectIdentityQuery aclObjectIdentityByObjectIdentityQuery;
private AclObjectIdentityInsert aclObjectIdentityInsert;
private ContactDelete contactDelete;
private ContactInsert contactInsert;
private ContactUpdate contactUpdate;
private ContactsAllQuery contactsAllQuery;
private ContactsByIdQuery contactsByIdQuery;
private PermissionDelete permissionDelete;
private PermissionInsert permissionInsert;
private PrincipalsAllQuery principalsAllQuery;
private RolesAllQuery rolesAllQuery;
//~ Methods ================================================================
public Contact getById(Integer id) {
List list = contactsByIdQuery.execute(id.intValue());
if (list.size() == 0) {
return null;
} else {
return (Contact) list.get(0);
}
}
public void create(Contact contact) {
contactInsert.insert(contact);
}
public Integer createAclObjectIdentity(Contact contact) {
return new Integer(aclObjectIdentityInsert.insert(makeObjectIdentity(
contact), null, SimpleAclEntry.class.getName()));
}
public void createPermission(Integer aclObjectIdentity, String recipient,
int permission) {
permissionInsert.insert(aclObjectIdentity, recipient,
new Integer(permission));
}
public void delete(Integer contactId) {
contactDelete.delete(contactId);
}
public void deletePermission(Integer aclObjectIdentity, String recipient) {
permissionDelete.delete(aclObjectIdentity, recipient);
}
public List findAll() {
return contactsAllQuery.execute();
}
public List findAllPrincipals() {
return principalsAllQuery.execute();
}
public List findAllRoles() {
return rolesAllQuery.execute();
}
public Integer lookupAclObjectIdentity(Contact contact) {
List list = aclObjectIdentityByObjectIdentityQuery.execute(makeObjectIdentity(
contact));
if (list.size() == 0) {
return null;
} else {
return (Integer) list.get(0);
}
}
public void update(Contact contact) {
contactUpdate.update(contact);
}
protected void initDao() throws Exception {
contactInsert = new ContactInsert(getDataSource());
contactUpdate = new ContactUpdate(getDataSource());
contactDelete = new ContactDelete(getDataSource());
aclObjectIdentityInsert = new AclObjectIdentityInsert(getDataSource());
permissionInsert = new PermissionInsert(getDataSource());
permissionDelete = new PermissionDelete(getDataSource());
contactsAllQuery = new ContactsAllQuery(getDataSource());
principalsAllQuery = new PrincipalsAllQuery(getDataSource());
rolesAllQuery = new RolesAllQuery(getDataSource());
contactsByIdQuery = new ContactsByIdQuery(getDataSource());
aclObjectIdentityByObjectIdentityQuery = new AclObjectIdentityByObjectIdentityQuery(getDataSource());
}
private String makeObjectIdentity(Contact contact) {
return contact.getClass().getName() + ":" + contact.getId();
}
//~ Inner Classes ==========================================================
protected class AclObjectIdentityByObjectIdentityQuery
extends MappingSqlQuery {
protected AclObjectIdentityByObjectIdentityQuery(DataSource ds) {
super(ds,
"SELECT id FROM acl_object_identity WHERE object_identity = ?");
declareParameter(new SqlParameter(Types.VARCHAR));
compile();
}
protected Object mapRow(ResultSet rs, int rownum)
throws SQLException {
return new Integer(rs.getInt("id"));
}
}
protected class AclObjectIdentityInsert extends SqlUpdate {
protected AclObjectIdentityInsert(DataSource ds) {
super(ds, "INSERT INTO acl_object_identity VALUES (?, ?, ?, ?)");
declareParameter(new SqlParameter(Types.INTEGER));
declareParameter(new SqlParameter(Types.VARCHAR));
declareParameter(new SqlParameter(Types.INTEGER));
declareParameter(new SqlParameter(Types.VARCHAR));
compile();
}
protected int insert(String objectIdentity,
Integer parentAclObjectIdentity, String aclClass) {
Object[] objs = new Object[] {null, objectIdentity, parentAclObjectIdentity, aclClass};
super.update(objs);
return getJdbcTemplate().queryForInt("call identity()");
}
}
protected class ContactDelete extends SqlUpdate {
protected ContactDelete(DataSource ds) {
super(ds, "DELETE FROM contacts WHERE id = ?");
declareParameter(new SqlParameter(Types.INTEGER));
compile();
}
protected void delete(Integer contactId) {
super.update(contactId.intValue());
}
}
protected class ContactInsert extends SqlUpdate {
protected ContactInsert(DataSource ds) {
super(ds, "INSERT INTO contacts VALUES (?, ?, ?)");
declareParameter(new SqlParameter(Types.INTEGER));
declareParameter(new SqlParameter(Types.VARCHAR));
declareParameter(new SqlParameter(Types.VARCHAR));
compile();
}
protected void insert(Contact contact) {
Object[] objs = new Object[] {contact.getId(), contact.getName(), contact
.getEmail()};
super.update(objs);
}
}
protected class ContactUpdate extends SqlUpdate {
protected ContactUpdate(DataSource ds) {
super(ds,
"UPDATE contacts SET contact_name = ?, address = ? WHERE id = ?");
declareParameter(new SqlParameter(Types.VARCHAR));
declareParameter(new SqlParameter(Types.VARCHAR));
declareParameter(new SqlParameter(Types.INTEGER));
compile();
}
protected void update(Contact contact) {
Object[] objs = new Object[] {contact.getName(), contact.getEmail(), contact
.getId()};
super.update(objs);
}
}
protected class ContactsAllQuery extends MappingSqlQuery {
protected ContactsAllQuery(DataSource ds) {
super(ds, "SELECT id, contact_name, email FROM contacts ORDER BY id");
compile();
}
protected Object mapRow(ResultSet rs, int rownum)
throws SQLException {
Contact contact = new Contact();
contact.setId(new Integer(rs.getInt("id")));
contact.setName(rs.getString("contact_name"));
contact.setEmail(rs.getString("email"));
return contact;
}
}
protected class ContactsByIdQuery extends MappingSqlQuery {
protected ContactsByIdQuery(DataSource ds) {
super(ds,
"SELECT id, contact_name, email FROM contacts WHERE id = ? ORDER BY id");
declareParameter(new SqlParameter(Types.INTEGER));
compile();
}
protected Object mapRow(ResultSet rs, int rownum)
throws SQLException {
Contact contact = new Contact();
contact.setId(new Integer(rs.getInt("id")));
contact.setName(rs.getString("contact_name"));
contact.setEmail(rs.getString("email"));
return contact;
}
}
protected class PermissionDelete extends SqlUpdate {
protected PermissionDelete(DataSource ds) {
super(ds,
"DELETE FROM acl_permission WHERE ACL_OBJECT_IDENTITY = ? AND RECIPIENT = ?");
declareParameter(new SqlParameter(Types.INTEGER));
declareParameter(new SqlParameter(Types.VARCHAR));
compile();
}
protected void delete(Integer aclObjectIdentity, String recipient) {
super.update(new Object[] {aclObjectIdentity, recipient});
}
}
protected class PermissionInsert extends SqlUpdate {
protected PermissionInsert(DataSource ds) {
super(ds, "INSERT INTO acl_permission VALUES (?, ?, ?, ?);");
declareParameter(new SqlParameter(Types.INTEGER));
declareParameter(new SqlParameter(Types.INTEGER));
declareParameter(new SqlParameter(Types.VARCHAR));
declareParameter(new SqlParameter(Types.INTEGER));
compile();
}
protected int insert(Integer aclObjectIdentity, String recipient,
Integer mask) {
Object[] objs = new Object[] {null, aclObjectIdentity, recipient, mask};
super.update(objs);
return getJdbcTemplate().queryForInt("call identity()");
}
}
protected class PrincipalsAllQuery extends MappingSqlQuery {
protected PrincipalsAllQuery(DataSource ds) {
super(ds, "SELECT username FROM users ORDER BY username");
compile();
}
protected Object mapRow(ResultSet rs, int rownum)
throws SQLException {
return rs.getString("username");
}
}
protected class RolesAllQuery extends MappingSqlQuery {
protected RolesAllQuery(DataSource ds) {
super(ds,
"SELECT DISTINCT authority FROM authorities ORDER BY authority");
compile();
}
protected Object mapRow(ResultSet rs, int rownum)
throws SQLException {
return rs.getString("authority");
}
}
}

View File

@ -15,8 +15,11 @@
package sample.contact;
import java.util.List;
/**
* Iterface for the application's business object.
* Interface for the application's services layer.
*
* @author Ben Alex
* @version $Id$
@ -24,15 +27,20 @@ package sample.contact;
public interface ContactManager {
//~ Methods ================================================================
public Contact[] getAllByOwner(String owner);
public List getAll();
public List getAllRecipients();
public Contact getById(Integer id);
public Integer getNextId();
public Contact getRandomContact();
public void addPermission(Contact contact, String recipient,
Integer permission);
public void create(Contact contact);
public void delete(Contact contact);
public void save(Contact contact);
public void deletePermission(Contact contact, String recipient);
}

View File

@ -15,159 +15,105 @@
package sample.contact;
import java.util.HashMap;
import java.util.Iterator;
import net.sf.acegisecurity.acl.basic.SimpleAclEntry;
import net.sf.acegisecurity.context.ContextHolder;
import net.sf.acegisecurity.context.SecureContext;
import org.springframework.beans.factory.InitializingBean;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Vector;
/**
* Backend business object that manages the contacts.
*
* <P>
* As a backend, it never faces the public callers. It is always accessed via
* the {@link ContactManagerFacade}.
* </p>
*
* <P>
* This facade approach is not really necessary in this application, and is
* done simply to demonstrate granting additional authorities via the
* <code>RunAsManager</code>.
* </p>
* Concrete implementation of {@link ContactManager}.
*
* @author Ben Alex
* @version $Id$
*/
public class ContactManagerBackend implements ContactManager {
public class ContactManagerBackend implements ContactManager, InitializingBean {
//~ Instance fields ========================================================
private Map contacts;
//~ Constructors ===========================================================
public ContactManagerBackend() {
this.contacts = new HashMap();
save(new Contact(this.getNextId(), "John Smith", "john@somewhere.com",
"marissa"));
save(new Contact(this.getNextId(), "Michael Citizen",
"michael@xyz.com", "marissa"));
save(new Contact(this.getNextId(), "Joe Bloggs", "joe@demo.com",
"marissa"));
save(new Contact(this.getNextId(), "Karen Sutherland",
"karen@sutherland.com", "dianne"));
save(new Contact(this.getNextId(), "Mitchell Howard",
"mitchell@abcdef.com", "dianne"));
save(new Contact(this.getNextId(), "Rose Costas", "rose@xyz.com",
"scott"));
save(new Contact(this.getNextId(), "Amanda Smith", "amanda@abcdef.com",
"scott"));
}
private ContactDao contactDao;
private int counter = 100;
//~ Methods ================================================================
/**
* Security system expects ROLE_RUN_AS_SERVER
*
* @param owner DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public Contact[] getAllByOwner(String owner) {
List list = new Vector();
Iterator iter = this.contacts.keySet().iterator();
while (iter.hasNext()) {
Integer contactId = (Integer) iter.next();
Contact contact = (Contact) this.contacts.get(contactId);
if (contact.getOwner().equals(owner)) {
list.add(contact);
}
}
if (list.size() == 0) {
return null;
} else {
return (Contact[]) list.toArray(new Contact[list.size()]);
}
public List getAll() {
return contactDao.findAll();
}
public List getAllRecipients() {
List list = contactDao.findAllPrincipals();
list.addAll(contactDao.findAllRoles());
return list;
}
/**
* Security system expects ROLE_RUN_AS_SERVER
*
* @param id DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public Contact getById(Integer id) {
return (Contact) this.contacts.get(id);
return contactDao.getById(id);
}
public void setContactDao(ContactDao contactDao) {
this.contactDao = contactDao;
}
public ContactDao getContactDao() {
return contactDao;
}
/**
* Public method
*
* @return DOCUMENT ME!
*/
public Integer getNextId() {
int max = 0;
Iterator iter = this.contacts.keySet().iterator();
while (iter.hasNext()) {
Integer id = (Integer) iter.next();
if (id.intValue() > max) {
max = id.intValue();
}
}
return new Integer(max + 1);
}
/**
* This is a public method, meaning a client could call this method
* directly (ie not via a facade). If this was an issue, the public method
* on the facade should not be public but secure. Quite possibly an
* AnonymousAuthenticationToken and associated provider could be used on a
* secure method, thus allowing a RunAsManager to protect the backend.
* This is a public method.
*
* @return DOCUMENT ME!
*/
public Contact getRandomContact() {
Random rnd = new Random();
int getNumber = rnd.nextInt(this.contacts.size()) + 1;
Iterator iter = this.contacts.keySet().iterator();
int i = 0;
List contacts = contactDao.findAll();
int getNumber = rnd.nextInt(contacts.size());
while (iter.hasNext()) {
i++;
return (Contact) contacts.get(getNumber);
}
Integer id = (Integer) iter.next();
public void addPermission(Contact contact, String recipient,
Integer permission) {
Integer aclObjectIdentity = contactDao.lookupAclObjectIdentity(contact);
contactDao.createPermission(aclObjectIdentity, recipient,
permission.intValue());
}
if (i == getNumber) {
return (Contact) this.contacts.get(id);
}
public void afterPropertiesSet() throws Exception {
if (contactDao == null) {
throw new IllegalArgumentException("contactDao required");
}
return null;
}
/**
* Security system expects ROLE_RUN_AS_SERVER
*
* @param contact DOCUMENT ME!
*/
public void create(Contact contact) {
// Create the Contact itself
contact.setId(new Integer(counter++));
contactDao.create(contact);
// Grant the current principal access to the contact
Integer aclObjectIdentity = contactDao.createAclObjectIdentity(contact);
contactDao.createPermission(aclObjectIdentity, getUsername(),
SimpleAclEntry.ADMINISTRATION);
}
public void delete(Contact contact) {
this.contacts.remove(contact.getId());
contactDao.delete(contact.getId());
}
/**
* Security system expects ROLE_RUN_AS_SERVER
*
* @param contact DOCUMENT ME!
*/
public void save(Contact contact) {
this.contacts.put(contact.getId(), contact);
public void deletePermission(Contact contact, String recipient) {
Integer aclObjectIdentity = contactDao.lookupAclObjectIdentity(contact);
contactDao.deletePermission(aclObjectIdentity, recipient);
}
public void update(Contact contact) {
contactDao.update(contact);
}
protected String getUsername() {
return ((SecureContext) ContextHolder.getContext()).getAuthentication()
.getPrincipal().toString();
}
}

View File

@ -1,149 +0,0 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import net.sf.acegisecurity.AccessDeniedException;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.UserDetails;
import net.sf.acegisecurity.context.ContextHolder;
import net.sf.acegisecurity.context.SecureContext;
import org.springframework.beans.factory.InitializingBean;
/**
* This is the public facade to the application's main business object.
*
* <p>
* Used to demonstrate security configuration in a multi-tier application. Most
* methods of this class are secured via standard security definitions in the
* bean context. There is one method that supplements these security checks.
* All methods delegate to a "backend" object. The "backend" object relies on
* the facade's <code>RunAsManager</code> assigning an additional
* <code>GrantedAuthority</code> that is required to call its methods.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class ContactManagerFacade implements ContactManager, InitializingBean {
//~ Instance fields ========================================================
private ContactManager backend;
//~ Methods ================================================================
/**
* Security system will ensure the owner parameter equals the currently
* logged in user.
*
* @param owner DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public Contact[] getAllByOwner(String owner) {
return backend.getAllByOwner(owner);
}
public void setBackend(ContactManager backend) {
this.backend = backend;
}
public ContactManager getBackend() {
return backend;
}
/**
* Security system will ensure logged in user has ROLE_TELLER.
*
* <p>
* Security system cannot ensure that only the owner can get the contact,
* as doing so would require it to specifically open the contact. Whilst
* possible, this would be expensive as the operation would be performed
* both by the security system as well as the implementation. Instead the
* facade will confirm the contact.getOwner() matches what is on the
* ContextHolder.
* </p>
*
* @param id DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws AccessDeniedException DOCUMENT ME!
*/
public Contact getById(Integer id) {
Contact result = backend.getById(id);
Authentication auth = ((SecureContext) ContextHolder.getContext())
.getAuthentication();
String username = auth.getPrincipal().toString();
if (auth.getPrincipal() instanceof UserDetails) {
username = ((UserDetails) auth.getPrincipal()).getUsername();
}
if (username.equals(result.getOwner())) {
return result;
} else {
throw new AccessDeniedException(
"The requested id is not owned by the currently logged in user");
}
}
/**
* Public method.
*
* @return DOCUMENT ME!
*/
public Integer getNextId() {
return backend.getNextId();
}
/**
* Public method.
*
* @return DOCUMENT ME!
*/
public Contact getRandomContact() {
return backend.getRandomContact();
}
public void afterPropertiesSet() throws Exception {
if (backend == null) {
throw new IllegalArgumentException(
"A backend ContactManager implementation is required");
}
}
/**
* Security system will ensure logged in user has ROLE_SUPERVISOR.
*
* @param contact DOCUMENT ME!
*/
public void delete(Contact contact) {
backend.delete(contact);
}
/**
* Security system will ensure the owner specified via contact.getOwner()
* equals the currently logged in user.
*
* @param contact DOCUMENT ME!
*/
public void save(Contact contact) {
backend.save(contact);
}
}

View File

@ -1,117 +0,0 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.ConfigAttribute;
import net.sf.acegisecurity.ConfigAttributeDefinition;
import net.sf.acegisecurity.UserDetails;
import net.sf.acegisecurity.vote.AccessDecisionVoter;
import org.aopalliance.intercept.MethodInvocation;
import java.util.Iterator;
/**
* Implementation of an {@link AccessDecisionVoter} that provides
* application-specific security for the Contact application.
*
* <p>
* If the {@link ConfigAttribute#getAttribute()} has a value of
* <code>CONTACT_OWNED_BY_CURRENT_USER</code>, the String or the
* Contact.getOwner() associated with the method call is compared with the
* Authentication.getPrincipal().toString() result. If it matches, the voter
* votes to grant access. If they do not match, it votes to deny access.
* </p>
*
* <p>
* All comparisons are case sensitive.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public class ContactSecurityVoter implements AccessDecisionVoter {
//~ Methods ================================================================
public boolean supports(ConfigAttribute attribute) {
if ("CONTACT_OWNED_BY_CURRENT_USER".equals(attribute.getAttribute())) {
return true;
} else {
return false;
}
}
public boolean supports(Class clazz) {
if (MethodInvocation.class.isAssignableFrom(clazz)) {
return true;
} else {
return false;
}
}
public int vote(Authentication authentication, Object object,
ConfigAttributeDefinition config) {
if ((object == null) || !this.supports(object.getClass())) {
throw new IllegalArgumentException(
"Does not support the presented Object type");
}
MethodInvocation invocation = (MethodInvocation) object;
int result = ACCESS_ABSTAIN;
Iterator iter = config.getConfigAttributes();
while (iter.hasNext()) {
ConfigAttribute attribute = (ConfigAttribute) iter.next();
if (this.supports(attribute)) {
result = ACCESS_DENIED;
// Lookup the account number being passed
String passedOwner = null;
for (int i = 0; i < invocation.getArguments().length; i++) {
Class argClass = invocation.getArguments()[i].getClass();
if (String.class.isAssignableFrom(argClass)) {
passedOwner = (String) invocation.getArguments()[i];
} else if (Contact.class.isAssignableFrom(argClass)) {
passedOwner = ((Contact) invocation.getArguments()[i])
.getOwner();
}
}
if (passedOwner != null) {
String username = authentication.getPrincipal().toString();
if (authentication.getPrincipal() instanceof UserDetails) {
username = ((UserDetails) authentication.getPrincipal())
.getUsername();
}
// Check the authentication principal matches the passed owner
if (passedOwner.equals(username)) {
return ACCESS_GRANTED;
}
}
}
}
return result;
}
}

View File

@ -0,0 +1,153 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
/**
* Populates the Contacts in-memory database with contact and ACL information.
*
* @author Ben Alex
* @version $Id$
*/
public class DataSourcePopulator implements InitializingBean {
//~ Instance fields ========================================================
private DataSource dataSource;
//~ Methods ================================================================
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public DataSource getDataSource() {
return dataSource;
}
public void afterPropertiesSet() throws Exception {
if (dataSource == null) {
throw new IllegalArgumentException("dataSource required");
}
JdbcTemplate template = new JdbcTemplate(dataSource);
template.execute(
"CREATE TABLE CONTACTS(ID INTEGER NOT NULL PRIMARY KEY, CONTACT_NAME VARCHAR_IGNORECASE(50) NOT NULL, EMAIL VARCHAR_IGNORECASE(50) NOT NULL)");
template.execute(
"INSERT INTO contacts VALUES (1, 'John Smith', 'john@somewhere.com');"); // marissa
template.execute(
"INSERT INTO contacts VALUES (2, 'Michael Citizen', 'michael@xyz.com');"); // marissa
template.execute(
"INSERT INTO contacts VALUES (3, 'Joe Bloggs', 'joe@demo.com');"); // marissa
template.execute(
"INSERT INTO contacts VALUES (4, 'Karen Sutherland', 'karen@sutherland.com');"); // marissa + dianne + scott
template.execute(
"INSERT INTO contacts VALUES (5, 'Mitchell Howard', 'mitchell@abcdef.com');"); // dianne
template.execute(
"INSERT INTO contacts VALUES (6, 'Rose Costas', 'rose@xyz.com');"); // dianne + scott
template.execute(
"INSERT INTO contacts VALUES (7, 'Amanda Smith', 'amanda@abcdef.com');"); // scott
template.execute(
"INSERT INTO contacts VALUES (8, 'Cindy Smith', 'cindy@smith.com');"); // dianne + scott
template.execute(
"INSERT INTO contacts VALUES (9, 'Jonathan Citizen', 'jonathan@xyz.com');"); // scott
template.execute(
"CREATE TABLE ACL_OBJECT_IDENTITY(ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,OBJECT_IDENTITY VARCHAR_IGNORECASE(250) NOT NULL,PARENT_OBJECT INTEGER,ACL_CLASS VARCHAR_IGNORECASE(250) NOT NULL,CONSTRAINT UNIQUE_OBJECT_IDENTITY UNIQUE(OBJECT_IDENTITY),CONSTRAINT SYS_FK_3 FOREIGN KEY(PARENT_OBJECT) REFERENCES ACL_OBJECT_IDENTITY(ID))");
template.execute(
"INSERT INTO acl_object_identity VALUES (1, 'sample.contact.Contact:1', null, 'net.sf.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (2, 'sample.contact.Contact:2', null, 'net.sf.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (3, 'sample.contact.Contact:3', null, 'net.sf.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (4, 'sample.contact.Contact:4', null, 'net.sf.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (5, 'sample.contact.Contact:5', null, 'net.sf.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (6, 'sample.contact.Contact:6', null, 'net.sf.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (7, 'sample.contact.Contact:7', null, 'net.sf.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (8, 'sample.contact.Contact:8', null, 'net.sf.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (9, 'sample.contact.Contact:9', null, 'net.sf.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"CREATE TABLE ACL_PERMISSION(ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,ACL_OBJECT_IDENTITY INTEGER NOT NULL,RECIPIENT VARCHAR_IGNORECASE(100) NOT NULL,MASK INTEGER NOT NULL,CONSTRAINT UNIQUE_RECIPIENT UNIQUE(ACL_OBJECT_IDENTITY,RECIPIENT),CONSTRAINT SYS_FK_7 FOREIGN KEY(ACL_OBJECT_IDENTITY) REFERENCES ACL_OBJECT_IDENTITY(ID))");
template.execute(
"INSERT INTO acl_permission VALUES (null, 1, 'marissa', 1);"); // administer
template.execute(
"INSERT INTO acl_permission VALUES (null, 2, 'marissa', 2);"); // read
template.execute(
"INSERT INTO acl_permission VALUES (null, 3, 'marissa', 22);"); // read+write+delete
template.execute(
"INSERT INTO acl_permission VALUES (null, 4, 'marissa', 1);"); // administer
template.execute(
"INSERT INTO acl_permission VALUES (null, 4, 'dianne', 1);"); // administer
template.execute(
"INSERT INTO acl_permission VALUES (null, 4, 'scott', 2);"); // read
template.execute(
"INSERT INTO acl_permission VALUES (null, 5, 'dianne', 2);"); // read
template.execute(
"INSERT INTO acl_permission VALUES (null, 6, 'dianne', 22);"); // read+write+delete
template.execute(
"INSERT INTO acl_permission VALUES (null, 6, 'scott', 2);"); // read
template.execute(
"INSERT INTO acl_permission VALUES (null, 7, 'scott', 1);"); // administer
template.execute(
"INSERT INTO acl_permission VALUES (null, 8, 'dianne', 2);"); // read
template.execute(
"INSERT INTO acl_permission VALUES (null, 8, 'scott', 2);"); // read
template.execute(
"INSERT INTO acl_permission VALUES (null, 9, 'scott', 22);"); // read+write+delete
template.execute(
"CREATE TABLE USERS(USERNAME VARCHAR_IGNORECASE(50) NOT NULL PRIMARY KEY,PASSWORD VARCHAR_IGNORECASE(50) NOT NULL,ENABLED BOOLEAN NOT NULL);");
template.execute(
"CREATE TABLE AUTHORITIES(USERNAME VARCHAR_IGNORECASE(50) NOT NULL,AUTHORITY VARCHAR_IGNORECASE(50) NOT NULL,CONSTRAINT FK_AUTHORITIES_USERS FOREIGN KEY(USERNAME) REFERENCES USERS(USERNAME));");
template.execute(
"CREATE UNIQUE INDEX IX_AUTH_USERNAME ON AUTHORITIES(USERNAME,AUTHORITY);");
/*
Passwords encoded using MD5, NOT in Base64 format, with null as salt
Encoded password for marissa is "koala"
Encoded password for dianne is "emu"
Encoded password for scott is "wombat"
Encoded password for peter is "opal" (but user is disabled)
*/
template.execute(
"INSERT INTO USERS VALUES('marissa','a564de63c2d0da68cf47586ee05984d7',TRUE);");
template.execute(
"INSERT INTO USERS VALUES('dianne','65d15fe9156f9c4bbffd98085992a44e',TRUE);");
template.execute(
"INSERT INTO USERS VALUES('scott','2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
template.execute(
"INSERT INTO USERS VALUES('peter','22b5c9accc6e1ba628cedc63a72d57f8',FALSE);");
template.execute(
"INSERT INTO AUTHORITIES VALUES('marissa','ROLE_USER');");
template.execute(
"INSERT INTO AUTHORITIES VALUES('marissa','ROLE_SUPERVISOR');");
template.execute(
"INSERT INTO AUTHORITIES VALUES('dianne','ROLE_USER');");
template.execute("INSERT INTO AUTHORITIES VALUES('scott','ROLE_USER');");
template.execute("INSERT INTO AUTHORITIES VALUES('peter','ROLE_USER');");
}
}

View File

@ -17,6 +17,7 @@ package sample.contact;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.bind.RequestUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
@ -28,7 +29,7 @@ import javax.servlet.http.HttpServletResponse;
/**
* Controller to delete a contact page.
* Controller to delete a contact.
*
* @author Ben Alex
* @version $Id$
@ -57,8 +58,8 @@ public class DeleteController implements Controller, InitializingBean {
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
Integer id = new Integer(request.getParameter("id"));
Contact contact = contactManager.getById(id);
int id = RequestUtils.getRequiredIntParameter(request, "contactId");
Contact contact = contactManager.getById(new Integer(id));
contactManager.delete(contact);
return new ModelAndView("deleted", "contact", contact);

View File

@ -0,0 +1,95 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import net.sf.acegisecurity.acl.AclManager;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.bind.RequestUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Controller for deleting an ACL permission.
*
* @author Ben Alex
* @version $Id$
*/
public class DeletePermissionController implements Controller, InitializingBean {
//~ Instance fields ========================================================
private AclManager aclManager;
private ContactManager contactManager;
//~ Methods ================================================================
public void setAclManager(AclManager aclManager) {
this.aclManager = aclManager;
}
public AclManager getAclManager() {
return aclManager;
}
public void setContactManager(ContactManager contact) {
this.contactManager = contact;
}
public ContactManager getContactManager() {
return contactManager;
}
public void afterPropertiesSet() throws Exception {
if (contactManager == null) {
throw new IllegalArgumentException(
"A ContactManager implementation is required");
}
if (aclManager == null) {
throw new IllegalArgumentException(
"An aclManager implementation is required");
}
}
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
int contactId = RequestUtils.getRequiredIntParameter(request,
"contactId");
String recipient = RequestUtils.getRequiredStringParameter(request,
"recipient");
Contact contact = contactManager.getById(new Integer(contactId));
contactManager.deletePermission(contact, recipient);
Map model = new HashMap();
model.put("contact", contact);
model.put("recipient", recipient);
return new ModelAndView("deletePermission", "model", model);
}
}

View File

@ -15,13 +15,6 @@
package sample.contact;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationCredentialsNotFoundException;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.UserDetails;
import net.sf.acegisecurity.context.ContextHolder;
import net.sf.acegisecurity.context.SecureContext;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.servlet.ModelAndView;
@ -30,6 +23,7 @@ import org.springframework.web.servlet.mvc.Controller;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
@ -67,38 +61,17 @@ public class SecureIndexController implements Controller, InitializingBean {
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
SecureContext secureContext = ((SecureContext) ContextHolder.getContext());
List myContactsList = contactManager.getAll();
Contact[] myContacts;
if (null == secureContext) {
throw new AuthenticationCredentialsNotFoundException(
"Authentication credentials were not found in the "
+ "SecureContext");
if (myContactsList.size() == 0) {
myContacts = null;
} else {
myContacts = (Contact[]) myContactsList.toArray(new Contact[] {});
}
// Lookup username. As we must accommodate DaoAuthenticationProvider,
// CAS and container based authentication, we take care with casting
Authentication auth = secureContext.getAuthentication();
String username = auth.getPrincipal().toString();
if (auth.getPrincipal() instanceof UserDetails) {
username = ((UserDetails) auth.getPrincipal()).getUsername();
}
boolean supervisor = false;
GrantedAuthority[] granted = auth.getAuthorities();
for (int i = 0; i < granted.length; i++) {
if (granted[i].getAuthority().equals("ROLE_SUPERVISOR")) {
supervisor = true;
}
}
Contact[] myContacts = contactManager.getAllByOwner(username);
Map model = new HashMap();
model.put("contacts", myContacts);
model.put("supervisor", new Boolean(supervisor));
model.put("user", username);
return new ModelAndView("index", "model", model);
}

View File

@ -15,19 +15,10 @@
package sample.contact;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.UserDetails;
import net.sf.acegisecurity.context.ContextHolder;
import net.sf.acegisecurity.context.SecureContext;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
import org.springframework.web.servlet.view.RedirectView;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@ -57,20 +48,8 @@ public class WebContactAddController extends SimpleFormController {
String name = ((WebContact) command).getName();
String email = ((WebContact) command).getEmail();
Authentication auth = ((SecureContext) ContextHolder.getContext())
.getAuthentication();
String owner = auth.getPrincipal().toString();
if (auth.getPrincipal() instanceof UserDetails) {
owner = ((UserDetails) auth.getPrincipal()).getUsername();
}
Contact contact = new Contact(contactManager.getNextId(), name, email,
owner);
contactManager.save(contact);
Map myModel = new HashMap();
myModel.put("now", new Date());
Contact contact = new Contact(name, email);
contactManager.create(contact);
return new ModelAndView(new RedirectView(getSuccessView()));
}

View File

@ -35,12 +35,16 @@ public class WebContactValidator implements Validator {
public void validate(Object obj, Errors errors) {
WebContact wc = (WebContact) obj;
if ((wc.getName() == null) || (wc.getName().length() < 3)) {
errors.rejectValue("name", "not-used", null, "Name is required.");
if ((wc.getName() == null) || (wc.getName().length() < 3)
|| (wc.getName().length() > 50)) {
errors.rejectValue("name", "err.name",
"Name 3-50 characters is required.");
}
if ((wc.getEmail() == null) || (wc.getEmail().length() < 3)) {
errors.rejectValue("email", "not-used", null, "Email is required.");
if ((wc.getEmail() == null) || (wc.getEmail().length() < 3)
|| (wc.getEmail().length() > 50)) {
errors.rejectValue("email", "err.email",
"Email 3-50 characters is required.");
}
}
}

View File

@ -0,0 +1,28 @@
# Global logging configuration
log4j.rootLogger=WARN, stdout, fileout
#log4j.logger.org.springframework.aop.framework.autoproxy=DEBUG, stdout, fileout
#log4j.logger.org.springframework.aop.framework.autoproxy.metadata=DEBUG, stdout, fileout
#log4j.logger.org.springframework.aop.framework.autoproxy.target=DEBUG, stdout, fileout
#log4j.logger.org.springframework.transaction.interceptor=DEBUG, stdout, fileout
#log4j.logger.net.sf.acegisecurity.intercept=DEBUG, stdout, fileout
#log4j.logger.net.sf.acegisecurity.intercept.method=DEBUG, stdout, fileout
#log4j.logger.net.sf.acegisecurity.afterinvocation=DEBUG, stdout, fileout
#log4j.logger.net.sf.acegisecurity.acl=DEBUG, stdout, fileout
#log4j.logger.net.sf.acegisecurity.acl.basic=DEBUG, stdout, fileout
#log4j.logger.net.sf.acegisecurity.taglibs.authz=DEBUG, stdout, fileout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.conversionPattern=[%p,%c{1},%t] %m%n
# Rolling log file output...
log4j.appender.fileout=org.apache.log4j.RollingFileAppender
log4j.appender.fileout.File=log4j.log
#log4j.appender.fileout.File=${webapp.root}/WEB-INF/log4j.log
log4j.appender.fileout.MaxFileSize=100KB
log4j.appender.fileout.MaxBackupIndex=1
log4j.appender.fileout.layout=org.apache.log4j.PatternLayout
log4j.appender.fileout.layout.conversionPattern=%d{ABSOLUTE} %5p %c{1},%t:%L - %m%n

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<!--
- Application context containing authentication, channel
- security and web URI beans.
-
- Only used by "ca" artifact.
-
- $Id$
-->
<beans>
<!-- ======================== AUTHENTICATION ======================= -->
<!-- We could also have a daoAuthenticationProvider in order to
process BASIC authentication requests, but this has been
left out given container adapters aren't recommended and
it would increase the number of bean declarations required -->
<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref local="authByAdapterProvider"/>
</list>
</property>
</bean>
<bean id="authByAdapterProvider" class="net.sf.acegisecurity.adapters.AuthByAdapterProvider">
<property name="key"><value>my_password</value></property>
</bean>
<bean id="httpRequestIntegrationFilter" class="net.sf.acegisecurity.adapters.HttpRequestIntegrationFilter"/>
<!-- ===================== HTTP CHANNEL REQUIREMENTS ==================== -->
<!-- Implement by servlet specification -->
<!-- ===================== HTTP REQUEST SECURITY ==================== -->
<!-- Implement by servlet specification -->
</beans>

View File

@ -1,142 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<!--
- Application context loaded by ContextLoaderListener if using container adapters
- $Id$
-->
<beans>
<!-- =================== SECURITY SYSTEM DEFINITIONS ================== -->
<!-- RunAsManager -->
<bean id="runAsManager" class="net.sf.acegisecurity.runas.RunAsManagerImpl">
<property name="key"><value>my_run_as_password</value></property>
</bean>
<!-- ~~~~~~~~~~~~~~~~~~~~ AUTHENTICATION DEFINITIONS ~~~~~~~~~~~~~~~~~~ -->
<bean id="runAsAuthenticationProvider" class="net.sf.acegisecurity.runas.RunAsImplAuthenticationProvider">
<property name="key"><value>my_run_as_password</value></property>
</bean>
<bean id="authByAdapterProvider" class="net.sf.acegisecurity.adapters.AuthByAdapterProvider">
<property name="key"><value>my_password</value></property>
</bean>
<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref local="runAsAuthenticationProvider"/>
<ref local="authByAdapterProvider"/>
<ref local="daoAuthenticationProvider"/>
</list>
</property>
</bean>
<bean id="inMemoryDaoImpl" class="net.sf.acegisecurity.providers.dao.memory.InMemoryDaoImpl">
<property name="userMap">
<value>
marissa=koala,ROLE_TELLER,ROLE_SUPERVISOR
dianne=emu,ROLE_TELLER
scott=wombat,ROLE_TELLER
peter=opal,disabled,ROLE_TELLER
</value>
</property>
</bean>
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="authenticationDao"><ref local="inMemoryDaoImpl"/></property>
</bean>
<bean id="basicProcessingFilter" class="net.sf.acegisecurity.ui.basicauth.BasicProcessingFilter">
<property name="authenticationManager"><ref local="authenticationManager"/></property>
<property name="authenticationEntryPoint"><ref local="basicProcessingFilterEntryPoint"/></property>
</bean>
<bean id="basicProcessingFilterEntryPoint" class="net.sf.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint">
<property name="realmName"><value>Contacts Realm</value></property>
</bean>
<bean id="autoIntegrationFilter" class="net.sf.acegisecurity.ui.AutoIntegrationFilter" />
<!-- ~~~~~~~~~~~~~~~~~~~~ AUTHORIZATION DEFINITIONS ~~~~~~~~~~~~~~~~~~~ -->
<!-- An access decision voter that reads ROLE_* configuaration settings -->
<bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/>
<!-- An access decision voter that reads CONTACT_OWNED_BY_CURRENT_USER configuaration settings -->
<bean id="contactSecurityVoter" class="sample.contact.ContactSecurityVoter"/>
<!-- An access decision manager used by the business objects -->
<bean id="businessAccessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions"><value>false</value></property>
<property name="decisionVoters">
<list>
<ref local="roleVoter"/>
<ref local="contactSecurityVoter"/>
</list>
</property>
</bean>
<!-- ===================== SECURITY DEFINITIONS ======================= -->
<bean id="publicContactManagerSecurity" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager"><ref local="authenticationManager"/></property>
<property name="accessDecisionManager"><ref local="businessAccessDecisionManager"/></property>
<property name="runAsManager"><ref local="runAsManager"/></property>
<property name="objectDefinitionSource">
<value>
sample.contact.ContactManager.delete=ROLE_SUPERVISOR,RUN_AS_SERVER
sample.contact.ContactManager.getAllByOwner=CONTACT_OWNED_BY_CURRENT_USER,RUN_AS_SERVER
sample.contact.ContactManager.save=CONTACT_OWNED_BY_CURRENT_USER,RUN_AS_SERVER
sample.contact.ContactManager.getById=ROLE_TELLER,RUN_AS_SERVER
</value>
</property>
</bean>
<!-- We expect all callers of the backend object to hold the role ROLE_RUN_AS_SERVER -->
<bean id="backendContactManagerSecurity" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager"><ref local="authenticationManager"/></property>
<property name="accessDecisionManager"><ref local="businessAccessDecisionManager"/></property>
<property name="runAsManager"><ref local="runAsManager"/></property>
<property name="objectDefinitionSource">
<value>
sample.contact.ContactManager.delete=ROLE_RUN_AS_SERVER
sample.contact.ContactManager.getAllByOwner=ROLE_RUN_AS_SERVER
sample.contact.ContactManager.save=ROLE_RUN_AS_SERVER
sample.contact.ContactManager.getById=ROLE_RUN_AS_SERVER
</value>
</property>
</bean>
<!-- ======================= BUSINESS DEFINITIONS ===================== -->
<bean id="contactManager" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>sample.contact.ContactManager</value></property>
<property name="interceptorNames">
<list>
<idref local="publicContactManagerSecurity"/>
<idref local="publicContactManagerTarget"/>
</list>
</property>
</bean>
<bean id="publicContactManagerTarget" class="sample.contact.ContactManagerFacade">
<property name="backend"><ref local="backendContactManager"/></property>
</bean>
<bean id="backendContactManager" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>sample.contact.ContactManager</value></property>
<property name="interceptorNames">
<list>
<idref local="backendContactManagerSecurity"/>
<idref local="backendContactManagerTarget"/>
</list>
</property>
</bean>
<bean id="backendContactManagerTarget" class="sample.contact.ContactManagerBackend"/>
</beans>

View File

@ -3,73 +3,65 @@
<!--
- Contacts web application
-
- web.xml for "ca" artifact only.
-
- $Id$
- File will be copied into WAR's WEB-INF directory if using container adapter
-->
<web-app>
<display-name>Contacts Sample Application</display-name>
<description>
Example of an application secured using Acegi Security System for Spring.
</description>
<!--
- Location of the XML file that defines the root application context
- Applied by ContextLoaderListener.
-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
<param-value>
/WEB-INF/applicationContext-acegi-security.xml
/WEB-INF/applicationContext-common-business.xml
/WEB-INF/applicationContext-common-authorization.xml
</param-value>
</context-param>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/classes/log4j.properties</param-value>
</context-param>
<!-- Obtains Authentication from HttpServletRequest.getPrincipal(),
and puts it into ContextHolder for request duration -->
<filter>
<filter-name>Acegi HTTP BASIC Authorization Filter</filter-name>
<filter-name>Acegi Security System for Spring HttpRequest Integration Filter</filter-name>
<filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>net.sf.acegisecurity.ui.basicauth.BasicProcessingFilter</param-value>
</init-param>
</filter>
<filter>
<filter-name>Acegi Security System for Spring Auto Integration Filter</filter-name>
<filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>net.sf.acegisecurity.ui.AutoIntegrationFilter</param-value>
<param-value>net.sf.acegisecurity.ui.webapp.HttpSessionIntegrationFilter</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Acegi HTTP BASIC Authorization Filter</filter-name>
<filter-name>Acegi Security System for Spring HttpRequest Integration Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>Acegi Security System for Spring Auto Integration Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--
- Loads the root application context of this web app at startup,
- by default from "/WEB-INF/applicationContext.xml".
- Use WebApplicationContextUtils.getWebApplicationContext(servletContext)
- to access it anywhere in the web application, outside of the framework.
- Loads the root application context of this web app at startup.
- The application context is then available via
- WebApplicationContextUtils.getWebApplicationContext(servletContext).
-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<!--
- Servlet that dispatches request to registered handlers (Controller implementations).
- Has its own application context, by default defined in "{servlet-name}-servlet.xml",
- i.e. "contacts-servlet.xml".
-
- A web app can contain any number of such servlets.
- Note that this web app does not have a shared root application context,
- therefore the DispatcherServlet contexts do not have a common parent.
- Provides core MVC application controller. See contacts-servlet.xml.
-->
<servlet>
<servlet-name>contacts</servlet-name>
@ -77,25 +69,20 @@
<load-on-startup>1</load-on-startup>
</servlet>
<!--
- Provides web services endpoint. See caucho-servlet.xml.
-->
<servlet>
<servlet-name>caucho</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<!--
- Maps the contacts dispatcher to /*.
-
-->
<servlet-mapping>
<servlet-name>contacts</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<!--
- Dispatcher servlet mapping for HTTP remoting via the Caucho protocols,
- i.e. Hessian and Burlap (see caucho-servlet.xml for the controllers).
-->
<servlet-mapping>
<servlet-name>caucho</servlet-name>
<url-pattern>/caucho/*</url-pattern>
@ -117,7 +104,7 @@
<url-pattern>/secure/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>ROLE_TELLER</role-name>
<role-name>ROLE_USER</role-name>
<role-name>ROLE_SUPERVISOR</role-name>
</auth-constraint>
</security-constraint>
@ -145,7 +132,7 @@
<role-name>ROLE_SUPERVISOR</role-name>
</security-role>
<security-role>
<role-name>ROLE_TELLER</role-name>
<role-name>ROLE_USER</role-name>
</security-role>
</web-app>

View File

@ -1,5 +1,4 @@
<%@ taglib prefix='c' uri='http://java.sun.com/jstl/core' %>
<%-- This page will be copied into WAR's root directory if using container adapter --%>
<html>
<head>
<title>Login</title>
@ -8,11 +7,12 @@
<body>
<h1>Login</h1>
<P>If you've used the standard springsecurity.xml, try these users:
<P>Valid users:
<P>
<P>username <b>marissa</b>, password <b>koala</b> (granted ROLE_SUPERVISOR)
<P>username <b>dianne</b>, password <b>emu</b> (not a supervisor)
<p>username <b>scott</b>, password <b>wombat</b> (not a supervisor)
<P>username <b>marissa</b>, password <b>koala</b>
<P>username <b>dianne</b>, password <b>emu</b>
<p>username <b>scott</b>, password <b>wombat</b>
<p>username <b>peter</b>, password <b>opal</b> (user disabled)
<p>
<%-- this form-login-page form is also used as the

View File

@ -2,60 +2,40 @@
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<!--
- Application context loaded by ContextLoaderListener if NOT using container adapters
- Application context containing authentication, channel
- security and web URI beans.
-
- Only used by "cas" artifact.
-
- $Id$
-
-
- HAVING PROBLEMS? See the etc/ssl/howto.txt file and read "TROUBLESHOOTING".
-
-
-->
<beans>
<!-- =================== SECURITY SYSTEM DEFINITIONS ================== -->
<!-- RunAsManager -->
<bean id="runAsManager" class="net.sf.acegisecurity.runas.RunAsManagerImpl">
<property name="key"><value>my_run_as_password</value></property>
</bean>
<!-- ======================== AUTHENTICATION ======================= -->
<!-- ~~~~~~~~~~~~~~~~~~~~ AUTHENTICATION DEFINITIONS ~~~~~~~~~~~~~~~~~~ -->
<bean id="runAsAuthenticationProvider" class="net.sf.acegisecurity.runas.RunAsImplAuthenticationProvider">
<property name="key"><value>my_run_as_password</value></property>
</bean>
<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref local="runAsAuthenticationProvider"/>
<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref local="casAuthenticationProvider"/>
</list>
</property>
</bean>
</list>
</property>
</bean>
<bean id="inMemoryDaoImpl" class="net.sf.acegisecurity.providers.dao.memory.InMemoryDaoImpl">
<property name="userMap">
<value>
marissa=PASSWORD_NOT_USED,ROLE_TELLER,ROLE_SUPERVISOR
dianne=PASSWORD_NOT_USED,ROLE_TELLER
scott=PASSWORD_NOT_USED,ROLE_TELLER
peter=PASSWORD_NOT_USED_AND_DISABLED_IGNORED,disabled,ROLE_TELLER
</value>
</property>
</bean>
<bean id="basicProcessingFilter" class="net.sf.acegisecurity.ui.basicauth.BasicProcessingFilter">
<property name="authenticationManager"><ref local="authenticationManager"/></property>
<property name="authenticationEntryPoint"><ref local="basicProcessingFilterEntryPoint"/></property>
</bean>
<bean id="jdbcDaoImpl" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl">
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
<bean id="basicProcessingFilterEntryPoint" class="net.sf.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint">
<property name="realmName"><value>Contacts Realm</value></property>
</bean>
<bean id="basicProcessingFilter" class="net.sf.acegisecurity.ui.basicauth.BasicProcessingFilter">
<property name="authenticationManager"><ref local="authenticationManager"/></property>
<property name="authenticationEntryPoint"><ref local="basicProcessingFilterEntryPoint"/></property>
</bean>
<bean id="autoIntegrationFilter" class="net.sf.acegisecurity.ui.AutoIntegrationFilter" />
<bean id="basicProcessingFilterEntryPoint" class="net.sf.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint">
<property name="realmName"><value>Contacts Realm</value></property>
</bean>
<bean id="httpSessionIntegrationFilter" class="net.sf.acegisecurity.ui.webapp.HttpSessionIntegrationFilter"/>
<bean id="casAuthenticationProvider" class="net.sf.acegisecurity.providers.cas.CasAuthenticationProvider">
<property name="casAuthoritiesPopulator"><ref local="casAuthoritiesPopulator"/></property>
@ -77,7 +57,7 @@
</bean>
<bean id="casAuthoritiesPopulator" class="net.sf.acegisecurity.providers.cas.populator.DaoCasAuthoritiesPopulator">
<property name="authenticationDao"><ref local="inMemoryDaoImpl"/></property>
<property name="authenticationDao"><ref local="jdbcDaoImpl"/></property>
</bean>
<bean id="casProxyDecider" class="net.sf.acegisecurity.providers.cas.proxy.RejectProxyTickets">
@ -88,86 +68,9 @@
<property name="sendRenew"><value>false</value></property>
</bean>
<!-- ~~~~~~~~~~~~~~~~~~~~ AUTHORIZATION DEFINITIONS ~~~~~~~~~~~~~~~~~~~ -->
<!-- An access decision voter that reads ROLE_* configuaration settings -->
<bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/>
<!-- An access decision voter that reads CONTACT_OWNED_BY_CURRENT_USER configuaration settings -->
<bean id="contactSecurityVoter" class="sample.contact.ContactSecurityVoter"/>
<!-- An access decision manager used by the business objects -->
<bean id="businessAccessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions"><value>false</value></property>
<property name="decisionVoters">
<list>
<ref local="roleVoter"/>
<ref local="contactSecurityVoter"/>
</list>
</property>
</bean>
<!-- ===================== SECURITY DEFINITIONS ======================= -->
<bean id="publicContactManagerSecurity" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager"><ref local="authenticationManager"/></property>
<property name="accessDecisionManager"><ref local="businessAccessDecisionManager"/></property>
<property name="runAsManager"><ref local="runAsManager"/></property>
<property name="objectDefinitionSource">
<value>
sample.contact.ContactManager.delete=ROLE_SUPERVISOR,RUN_AS_SERVER
sample.contact.ContactManager.getAllByOwner=CONTACT_OWNED_BY_CURRENT_USER,RUN_AS_SERVER
sample.contact.ContactManager.save=CONTACT_OWNED_BY_CURRENT_USER,RUN_AS_SERVER
sample.contact.ContactManager.getById=ROLE_TELLER,RUN_AS_SERVER
</value>
</property>
</bean>
<!-- We expect all callers of the backend object to hold the role ROLE_RUN_AS_SERVER -->
<bean id="backendContactManagerSecurity" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager"><ref local="authenticationManager"/></property>
<property name="accessDecisionManager"><ref local="businessAccessDecisionManager"/></property>
<property name="runAsManager"><ref local="runAsManager"/></property>
<property name="objectDefinitionSource">
<value>
sample.contact.ContactManager.delete=ROLE_RUN_AS_SERVER
sample.contact.ContactManager.getAllByOwner=ROLE_RUN_AS_SERVER
sample.contact.ContactManager.save=ROLE_RUN_AS_SERVER
sample.contact.ContactManager.getById=ROLE_RUN_AS_SERVER
</value>
</property>
</bean>
<!-- ======================= BUSINESS DEFINITIONS ===================== -->
<bean id="contactManager" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>sample.contact.ContactManager</value></property>
<property name="interceptorNames">
<list>
<idref local="publicContactManagerSecurity"/>
<idref local="publicContactManagerTarget"/>
</list>
</property>
</bean>
<bean id="publicContactManagerTarget" class="sample.contact.ContactManagerFacade">
<property name="backend"><ref local="backendContactManager"/></property>
</bean>
<bean id="backendContactManager" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>sample.contact.ContactManager</value></property>
<property name="interceptorNames">
<list>
<idref local="backendContactManagerSecurity"/>
<idref local="backendContactManagerTarget"/>
</list>
</property>
</bean>
<bean id="backendContactManagerTarget" class="sample.contact.ContactManagerBackend"/>
<!-- ===================== HTTP CHANNEL REQUIREMENTS ==================== -->
<!-- Enabled by default for CAS, as a CAS deployment uses HTTPS -->
<bean id="channelProcessingFilter" class="net.sf.acegisecurity.securechannel.ChannelProcessingFilter">
<property name="channelDecisionManager"><ref local="channelDecisionManager"/></property>
<property name="filterInvocationDefinitionSource">
@ -194,6 +97,11 @@
<!-- ===================== HTTP REQUEST SECURITY ==================== -->
<bean id="securityEnforcementFilter" class="net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter">
<property name="filterSecurityInterceptor"><ref local="filterInvocationInterceptor"/></property>
<property name="authenticationEntryPoint"><ref local="casProcessingFilterEntryPoint"/></property>
</bean>
<bean id="casProcessingFilter" class="net.sf.acegisecurity.ui.cas.CasProcessingFilter">
<property name="authenticationManager"><ref local="authenticationManager"/></property>
<property name="authenticationFailureUrl"><value>/casfailed.jsp</value></property>
@ -201,11 +109,6 @@
<property name="filterProcessesUrl"><value>/j_acegi_cas_security_check</value></property>
</bean>
<bean id="securityEnforcementFilter" class="net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter">
<property name="filterSecurityInterceptor"><ref local="filterInvocationInterceptor"/></property>
<property name="authenticationEntryPoint"><ref local="casProcessingFilterEntryPoint"/></property>
</bean>
<bean id="casProcessingFilterEntryPoint" class="net.sf.acegisecurity.ui.cas.CasProcessingFilterEntryPoint">
<property name="loginUrl"><value>https://localhost:8443/cas/login</value></property>
<property name="serviceProperties"><ref local="serviceProperties"/></property>
@ -215,7 +118,7 @@
<property name="allowIfAllAbstainDecisions"><value>false</value></property>
<property name="decisionVoters">
<list>
<ref local="roleVoter"/>
<ref bean="roleVoter"/>
</list>
</property>
</bean>
@ -226,7 +129,6 @@
<bean id="filterInvocationInterceptor" class="net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager"><ref local="authenticationManager"/></property>
<property name="accessDecisionManager"><ref local="httpRequestAccessDecisionManager"/></property>
<property name="runAsManager"><ref local="runAsManager"/></property>
<property name="objectDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON

View File

@ -3,17 +3,33 @@
<!--
- Contacts web application
-
- web.xml for "cas" artifact only.
-
- $Id$
- File will be copied into WAR's WEB-INF directory if NOT using container adapter
-->
<web-app>
<display-name>Contacts Sample Application</display-name>
<description>
Example of an application secured using Acegi Security System for Spring.
</description>
<!--
- Location of the XML file that defines the root application context
- Applied by ContextLoaderListener.
-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext-acegi-security.xml
/WEB-INF/applicationContext-common-business.xml
/WEB-INF/applicationContext-common-authorization.xml
</param-value>
</context-param>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/classes/log4j.properties</param-value>
</context-param>
<!-- Required for CAS ProxyTicketReceptor servlet. This is the
URL to CAS' "proxy" actuator, where a PGT and TargetService can
@ -24,15 +40,6 @@
<param-value>http://localhost:8433/cas/proxy</param-value>
</context-param>
<!--
- Location of the XML file that defines the root application context
- Applied by ContextLoaderListener.
-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<filter>
<filter-name>Acegi Channel Processing Filter</filter-name>
<filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
@ -42,6 +49,7 @@
</init-param>
</filter>
<!-- Responds to HTTP POSTs to j_acegi_cas_security_check URI -->
<filter>
<filter-name>Acegi CAS Processing Filter</filter-name>
<filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
@ -51,6 +59,7 @@
</init-param>
</filter>
<!-- Responds to HTTP requests with a BASIC (RFC 1945) authentication header -->
<filter>
<filter-name>Acegi HTTP BASIC Authorization Filter</filter-name>
<filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
@ -60,15 +69,21 @@
</init-param>
</filter>
<!-- Obtains Authentication from HttpSession attribute, puts it into
ContextHolder for request duration, proceeds with request, then
copies Authentication from ContextHolder back into HttpSession -->
<filter>
<filter-name>Acegi Security System for Spring Auto Integration Filter</filter-name>
<filter-name>Acegi Security System for Spring HttpSession Integration Filter</filter-name>
<filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>net.sf.acegisecurity.ui.AutoIntegrationFilter</param-value>
<param-value>net.sf.acegisecurity.ui.webapp.HttpSessionIntegrationFilter</param-value>
</init-param>
</filter>
<!-- Provides HTTP request URL security, and also catches
AcegiSecurityExceptions and sends 403 errors (if access denied)
or commences an authentication mechanism as appropriate -->
<filter>
<filter-name>Acegi HTTP Request Security Filter</filter-name>
<filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
@ -77,12 +92,12 @@
<param-value>net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Acegi Channel Processing Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>Acegi CAS Processing Filter</filter-name>
<url-pattern>/*</url-pattern>
@ -94,7 +109,7 @@
</filter-mapping>
<filter-mapping>
<filter-name>Acegi Security System for Spring Auto Integration Filter</filter-name>
<filter-name>Acegi Security System for Spring HttpSession Integration Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
@ -104,23 +119,20 @@
</filter-mapping>
<!--
- Loads the root application context of this web app at startup,
- by default from "/WEB-INF/applicationContext.xml".
- Use WebApplicationContextUtils.getWebApplicationContext(servletContext)
- to access it anywhere in the web application, outside of the framework.
- Loads the root application context of this web app at startup.
- The application context is then available via
- WebApplicationContextUtils.getWebApplicationContext(servletContext).
-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<!--
- Servlet that dispatches request to registered handlers (Controller implementations).
- Has its own application context, by default defined in "{servlet-name}-servlet.xml",
- i.e. "contacts-servlet.xml".
-
- A web app can contain any number of such servlets.
- Note that this web app does not have a shared root application context,
- therefore the DispatcherServlet contexts do not have a common parent.
- Provides core MVC application controller. See contacts-servlet.xml.
-->
<servlet>
<servlet-name>contacts</servlet-name>
@ -128,44 +140,25 @@
<load-on-startup>1</load-on-startup>
</servlet>
<!--
- Provides web services endpoint. See caucho-servlet.xml.
-->
<servlet>
<servlet-name>caucho</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<!-- CAS servlet which receives a proxy-granting ticket from the CAS
server. THIS CAN BE REMOVED IF THE APPLICATION DOESN'T NEED TO
ACT AS A PROXY -->
<servlet>
<servlet-name>casproxy</servlet-name>
<servlet-class>edu.yale.its.tp.cas.proxy.ProxyTicketReceptor</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>
<!--
- Maps the contacts dispatcher to /*.
-
-->
<servlet-mapping>
<servlet-name>contacts</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<!--
- Dispatcher servlet mapping for HTTP remoting via the Caucho protocols,
- i.e. Hessian and Burlap (see caucho-servlet.xml for the controllers).
-->
<servlet-mapping>
<servlet-name>caucho</servlet-name>
<url-pattern>/caucho/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>casproxy</servlet-name>
<url-pattern>/casProxy/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
@ -174,5 +167,5 @@
<taglib-uri>/spring</taglib-uri>
<taglib-location>/WEB-INF/spring.tld</taglib-location>
</taglib>
</web-app>

View File

@ -1,7 +1,6 @@
<%@ taglib prefix='c' uri='http://java.sun.com/jstl/core' %>
<%@ page import="net.sf.acegisecurity.ui.AbstractProcessingFilter" %>
<%@ page import="net.sf.acegisecurity.AuthenticationException" %>
<%-- This page will be copied into WAR's root directory if using CAS --%>
<html>
<head>

View File

@ -0,0 +1,151 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<!--
- Application context containing authentication beans.
-
- Used by all artifacts.
-
- $Id$
-->
<beans>
<!-- ~~~~~~~~~~~~~~~~~~ "BEFORE INVOCATION" AUTHORIZATION DEFINITIONS ~~~~~~~~~~~~~~~~ -->
<!-- An access decision voter that reads ROLE_* configuration settings -->
<bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/>
<!-- An access decision voter that reads ACL_CONTACT_READ configuration settings -->
<bean id="aclContactReadVoter" class="net.sf.acegisecurity.vote.BasicAclEntryVoter">
<property name="processConfigAttribute"><value>ACL_CONTACT_READ</value></property>
<property name="processDomainObjectClass"><value>sample.contact.Contact</value></property>
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<value>1</value> <!-- SimpleAclEntry.ADMINISTER -->
<value>2</value> <!-- SimpleAclEntry.READ -->
</list>
</property>
</bean>
<!-- An access decision voter that reads ACL_CONTACT_DELETE configuration settings -->
<bean id="aclContactDeleteVoter" class="net.sf.acegisecurity.vote.BasicAclEntryVoter">
<property name="processConfigAttribute"><value>ACL_CONTACT_DELETE</value></property>
<property name="processDomainObjectClass"><value>sample.contact.Contact</value></property>
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<value>1</value> <!-- SimpleAclEntry.ADMINISTER -->
<value>16</value> <!-- SimpleAclEntry.DELETE -->
</list>
</property>
</bean>
<!-- An access decision voter that reads ACL_CONTACT_ADMIN configuration settings -->
<bean id="aclContactAdminVoter" class="net.sf.acegisecurity.vote.BasicAclEntryVoter">
<property name="processConfigAttribute"><value>ACL_CONTACT_ADMIN</value></property>
<property name="processDomainObjectClass"><value>sample.contact.Contact</value></property>
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<value>1</value> <!-- SimpleAclEntry.ADMINISTER -->
</list>
</property>
</bean>
<!-- An access decision manager used by the business objects -->
<bean id="businessAccessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions"><value>false</value></property>
<property name="decisionVoters">
<list>
<ref local="roleVoter"/>
<ref local="aclContactReadVoter"/>
<ref local="aclContactDeleteVoter"/>
<ref local="aclContactAdminVoter"/>
</list>
</property>
</bean>
<!-- ========= ACCESS CONTROL LIST LOOKUP MANAGER DEFINITIONS ========= -->
<bean id="aclManager" class="net.sf.acegisecurity.acl.AclProviderManager">
<property name="providers">
<list>
<ref local="basicAclProvider"/>
</list>
</property>
</bean>
<bean id="basicAclProvider" class="net.sf.acegisecurity.acl.basic.BasicAclProvider">
<property name="basicAclDao"><ref local="basicAclDao"/></property>
</bean>
<bean id="basicAclDao" class="net.sf.acegisecurity.acl.basic.jdbc.JdbcDaoImpl">
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
<!-- ============== "AFTER INTERCEPTION" AUTHORIZATION DEFINITIONS =========== -->
<bean id="afterInvocationManager" class="net.sf.acegisecurity.afterinvocation.AfterInvocationProviderManager">
<property name="providers">
<list>
<ref local="afterAclRead"/>
<ref local="afterAclCollectionRead"/>
</list>
</property>
</bean>
<!-- Processes AFTER_ACL_COLLECTION_READ configuration settings -->
<bean id="afterAclCollectionRead" class="net.sf.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationCollectionFilteringProvider">
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<value>1</value> <!-- SimpleAclEntry.ADMINISTER -->
<value>2</value> <!-- SimpleAclEntry.READ -->
</list>
</property>
</bean>
<!-- Processes AFTER_ACL_READ configuration settings -->
<bean id="afterAclRead" class="net.sf.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationProvider">
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<value>1</value> <!-- SimpleAclEntry.ADMINISTER -->
<value>2</value> <!-- SimpleAclEntry.READ -->
</list>
</property>
</bean>
<!-- ================= METHOD INVOCATION AUTHORIZATION ==================== -->
<!-- getRandomContact() is public.
The create, getAll, getById etc have ROLE_USER to ensure user is
authenticated (all users hold ROLE_USER in this application).
The delete and update methods don't need a ROLE_USER as they will
ensure the user is authenticated via their ACL_CONTACT_DELETE or
ACL_CONTACT_READ attribute, which also ensures the user has permission
to the Contact presented as a method argument.
-->
<bean id="contactManagerSecurity" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="accessDecisionManager"><ref local="businessAccessDecisionManager"/></property>
<property name="afterInvocationManager"><ref local="afterInvocationManager"/></property>
<property name="objectDefinitionSource">
<value>
sample.contact.ContactManager.create=ROLE_USER
sample.contact.ContactManager.getAllRecipients=ROLE_USER
sample.contact.ContactManager.getAll=ROLE_USER,AFTER_ACL_COLLECTION_READ
sample.contact.ContactManager.getById=ROLE_USER,AFTER_ACL_READ
sample.contact.ContactManager.delete=ACL_CONTACT_DELETE
sample.contact.ContactManager.deletePermission=ACL_CONTACT_ADMIN
sample.contact.ContactManager.addPermission=ACL_CONTACT_ADMIN
</value>
</property>
</bean>
</beans>

View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<!--
- Application context containing business beans.
-
- Used by all artifacts.
-
- $Id$
-->
<beans>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>org.hsqldb.jdbcDriver</value>
</property>
<property name="url">
<value>jdbc:hsqldb:mem:contacts</value>
</property>
<property name="username">
<value>sa</value>
</property>
<property name="password">
<value></value>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource"><ref local="dataSource"/></property>
</bean>
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager"><ref bean="transactionManager"/></property>
<property name="transactionAttributeSource">
<value>
sample.contact.ContactManager.create=PROPAGATION_REQUIRED
sample.contact.ContactManager.getAllRecipients=PROPAGATION_REQUIRED,readOnly
sample.contact.ContactManager.getAll=PROPAGATION_REQUIRED,readOnly
sample.contact.ContactManager.getById=PROPAGATION_REQUIRED,readOnly
sample.contact.ContactManager.delete=PROPAGATION_REQUIRED
sample.contact.ContactManager.deletePermission=PROPAGATION_REQUIRED
sample.contact.ContactManager.addPermission=PROPAGATION_REQUIRED
</value>
</property>
</bean>
<bean id="dataSourcePopulator" class="sample.contact.DataSourcePopulator">
<property name="dataSource"><ref local="dataSource"/></property>
</bean>
<bean id="contactDao" class="sample.contact.ContactDaoSpring">
<property name="dataSource"><ref local="dataSource"/></property>
</bean>
<bean id="contactManager" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>sample.contact.ContactManager</value></property>
<property name="interceptorNames">
<list>
<idref local="transactionInterceptor"/>
<idref bean="contactManagerSecurity"/>
<idref local="contactManagerTarget"/>
</list>
</property>
</bean>
<bean id="contactManagerTarget" class="sample.contact.ContactManagerBackend">
<property name="contactDao"><ref local="contactDao"/></property>
</bean>
</beans>

View File

@ -3,6 +3,7 @@
<!--
- Application context definition for "contacts" DispatcherServlet.
-
- $Id$
-->
@ -22,6 +23,16 @@
<property name="contactManager"><ref bean="contactManager"/></property>
</bean>
<bean id="adminPermissionController" class="sample.contact.AdminPermissionController">
<property name="contactManager"><ref bean="contactManager"/></property>
<property name="aclManager"><ref bean="aclManager"/></property>
</bean>
<bean id="deletePermissionController" class="sample.contact.DeletePermissionController">
<property name="contactManager"><ref bean="contactManager"/></property>
<property name="aclManager"><ref bean="aclManager"/></property>
</bean>
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
@ -29,11 +40,17 @@
<prop key="/secure/add.htm">secureAddForm</prop>
<prop key="/secure/index.htm">secureIndexController</prop>
<prop key="/secure/del.htm">secureDeleteController</prop>
<prop key="/secure/adminPermission.htm">adminPermissionController</prop>
<prop key="/secure/deletePermission.htm">deletePermissionController</prop>
<prop key="/secure/addPermission.htm">addPermissionForm</prop>
</props>
</property>
</bean>
<bean id="addValidator" class="sample.contact.WebContactValidator"/>
<bean id="addPermissionValidator" class="sample.contact.AddPermissionValidator"/>
<bean id="secureAddForm" class="sample.contact.WebContactAddController">
<property name="sessionForm"><value>true</value></property>
<property name="commandName"><value>webContact</value></property>
@ -46,6 +63,18 @@
</property>
</bean>
<bean id="addPermissionForm" class="sample.contact.AddPermissionController">
<property name="sessionForm"><value>true</value></property>
<property name="commandName"><value>addPermission</value></property>
<property name="commandClass"><value>sample.contact.AddPermission</value></property>
<property name="validator"><ref bean="addPermissionValidator"/></property>
<property name="formView"><value>addPermission</value></property>
<property name="successView"><value>index.htm</value></property>
<property name="contactManager">
<ref bean="contactManager"/>
</property>
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix"><value>/WEB-INF/jsp/</value></property>
<property name="suffix"><value>.jsp</value></property>

View File

@ -0,0 +1,55 @@
<%@ include file="/WEB-INF/jsp/include.jsp" %>
<html>
<head><title>Add Permission</title></head>
<body>
<h1>Add Permission</h1>
<form method="post">
<table width="95%" bgcolor="f8f8ff" border="0" cellspacing="0" cellpadding="5">
<tr>
<td alignment="right" width="20%">Contact:</td>
<td width="60%"><c:out value="${addPermission.contact}"/></td>
</tr>
<tr>
<td alignment="right" width="20%">Recipient:</td>
<spring:bind path="addPermission.recipient">
<td width="20%">
<select name="<c:out value="${status.expression}"/>">
<c:forEach var="thisRecipient" items="${recipients}">
<option <c:if test="${thisRecipient.key == status.value}">selected</c:if> value="<c:out value="${thisRecipient.key}"/>">
<c:out value="${thisRecipient.value}"/></option>
</c:forEach>
</select>
</td>
<td width="60%">
<font color="red"><c:out value="${status.errorMessage}"/></font>
</td>
</spring:bind>
</tr>
<tr>
<td alignment="right" width="20%">Permission:</td>
<spring:bind path="addPermission.permission">
<td width="20%">
<select name="<c:out value="${status.expression}"/>">
<c:forEach var="thisPermission" items="${permissions}">
<option <c:if test="${thisPermission.key == status.value}">selected</c:if> value="<c:out value="${thisPermission.key}"/>">
<c:out value="${thisPermission.value}"/></option>
</c:forEach>
</select>
</td>
<td width="60%">
<font color="red"><c:out value="${status.errorMessage}"/></font>
</td>
</spring:bind>
</tr>
</table>
<br>
<spring:hasBindErrors name="webContact">
<b>Please fix all errors!</b>
</spring:hasBindErrors>
<br><br>
<input name="execute" type="submit" alignment="center" value="Execute">
</form>
<p>
<A HREF="<c:url value="adminPermission.htm"><c:param name="contactId" value="${addPermission.contact.id}"/></c:url>">Admin Permission</A> <a href="<c:url value="index.htm"/>">Manage</a>
</body>
</html>

View File

@ -0,0 +1,39 @@
<%@ page import="net.sf.acegisecurity.acl.basic.SimpleAclEntry" %>
<%@ include file="/WEB-INF/jsp/include.jsp" %>
<html>
<head><title>Administer Permissions</title></head>
<body>
<h1>Administer Permissions</h1>
<P>
<code>
<c:out value="${model.contact}"/>
</code>
<P>
<table cellpadding=3 border=0>
<c:forEach var="acl" items="${model.acls}">
<c:if test="${acl.class.name eq 'net.sf.acegisecurity.acl.basic.SimpleAclEntry'}">
<tr>
<td>
<code>
<%
SimpleAclEntry simpleAcl = ((SimpleAclEntry) pageContext.getAttribute("acl"));
String permissionBlock = simpleAcl.printPermissionsBlock();
%>
<%= permissionBlock %>
[<c:out value="${acl.mask}"/>]
<c:out value="${acl.recipient}"/>
</code>
</td>
<td>
<!-- This application doesn't use ACL inheritance, so we can safely use
the model's contact and know it was directly assigned the ACL -->
<A HREF="<c:url value="deletePermission.htm"><c:param name="contactId" value="${model.contact.id}"/><c:param name="recipient" value="${acl.recipient}"/></c:url>">Del</A>
</td>
</tr>
</c:if>
</c:forEach>
</table>
<p><a href="<c:url value="addPermission.htm"><c:param name="contactId" value="${model.contact.id}"/></c:url>">Add Permission</a> <a href="<c:url value="index.htm"/>">Manage</a>
</body>
</html>

View File

@ -0,0 +1,18 @@
<%@ page import="net.sf.acegisecurity.acl.basic.SimpleAclEntry" %>
<%@ include file="/WEB-INF/jsp/include.jsp" %>
<html>
<head><title>Permission Deleted</title></head>
<body>
<h1>Permission Deleted</h1>
<P>
<code>
<c:out value="${model.contact}"/>
</code>
<P>
<code>
<c:out value="${model.recipient}"/>
</code>
<p><a href="<c:url value="index.htm"/>">Manage</a>
</body>
</html>

View File

@ -4,28 +4,42 @@
<head><title>Contacts Security Demo</title></head>
<body>
<h1>Contacts Security Demo</h1>
<p>This is a very simple application to demonstrate the Acegi Security System for Spring.
The application manages contacts, partitioned based on the user that owns them.
Users may only manage their own contacts, and only users with ROLE_SUPERVISOR
are allowed to delete their contacts. It also demonstrates how to configure
server-side secure objects so they can only be accessed via a public facade.
<P>Contacts demonstrates the following central Acegi Security capabilities:
<ul>
<li><b>Role-based security</b>. Each principal is a member of certain roles,
which are used to restrict access to certain secure objects.</li>
<li><b>Domain object instance security</b>. The <code>Contact</code>, the
main domain object in the application, has an access control list (ACL)
that indicates who is allowed read, administer and delete the object.</li>
<li><b>Method invocation security</b>. The <code>ContactManager</code> service
layer bean has a number of secured (protected) and public (unprotected)
methods.</li>
<li><b>Web request security</b>. The <code>/secure</code> URI path is protected
by Acegi Security from principals not holding the
<code>ROLE_USER</code> granted authority.</li>
<li><b>Security unaware application objects</b>. None of the objects
are aware of the security being implemented by Acegi Security. *</li>
<li><b>Security taglib usage</b>. All of the JSPs use Acegi Security's
taglib to evaluate security information. *</li>
<li><b>Fully declarative security</b>. Every capability is configured in
the application context using standard Acegi Security classes. *</li>
<li><b>Database-sourced security data</b>. All of the user, role and ACL
information is obtained from an in-memory JDBC-compliant database.</li>
</ul>
<P>If you deployed the contacts-container-adapter.war file, the application
automatically extracts the principal from the web container (which should be
configured with a suitable Acegi Security System for Spring adapter). If
you're using the standard contacts.war file, the application is entirely
self-contained and you don't need to do anything special with your web
container. If you're using the contacts-cas.war file, please review the
setup in samples/contacts/etc/cas/applicationContext.xml for your CAS server
and if necessary rebuild using the Contacts application's build.xml.
* As the application provides an "ACL Administration" use case, those
classes are necessarily aware of security. But no business use cases are.
<P>This application also demonstrates a public method, which is used to select
the random contact that is shown below:
<P>
<p>Please excuse the lack of look 'n' feel polish in this application.
It is about security, after all! :-)
<p>To demonstrate a public method on <code>ContactManager</code>,
here's a random <code>Contact</code>:
<p>
<code>
<c:out value="${contact}"/>
</code>
<p>
<p>Get started by clicking "Manage"...
<p><A HREF="<c:url value="secure/index.htm"/>">Manage</a>
<A HREF="<c:url value="secure/debug.jsp"/>">Debug</a>
</body>

View File

@ -3,7 +3,7 @@
<html>
<head><title>Your Contacts</title></head>
<body>
<h1><c:out value="${model.user}"/>'s Contacts</h1>
<h1><authz:authentication operation="principal"/>'s Contacts</h1>
<P>
<table cellpadding=3 border=0>
<tr><td><b>id</b></td><td><b>Name</b></td><td><b>Email</b></td></tr>
@ -18,9 +18,12 @@
<td>
<c:out value="${contact.email}"/>
</td>
<authz:authorize ifAllGranted="ROLE_SUPERVISOR">
<td><A HREF="<c:url value="del.htm"><c:param name="id" value="${contact.id}"/></c:url>">Del</A></td>
</authz:authorize>
<authz:acl domainObject="${contact}" hasPermission="16,1">
<td><A HREF="<c:url value="del.htm"><c:param name="contactId" value="${contact.id}"/></c:url>">Del</A></td>
</authz:acl>
<authz:acl domainObject="${contact}" hasPermission="1">
<td><A HREF="<c:url value="adminPermission.htm"><c:param name="contactId" value="${contact.id}"/></c:url>">Admin Permission</A></td>
</authz:acl>
</tr>
</c:forEach>
</table>

View File

@ -27,21 +27,20 @@ if (context != null) { %>
if (auth instanceof AuthByAdapter) { %>
<BR><B>SUCCESS! Your container adapter appears to be properly configured!</B><BR><BR>
<% } else { %>
<BR><B>SUCCESS! Your web filter appears to be properly configured!</B><BR>
<BR><B>SUCCESS! Your web filters appear to be properly configured!</B><BR>
<% }
} else { %>
Authentication object is null.<BR>
This is an error and your container adapter will not operate properly until corrected.<BR><BR>
This is an error and your Acegi Security application will not operate properly until corrected.<BR><BR>
<% }
} else { %>
<B>ContextHolder does not contain a SecureContext.</B><BR>
This is an error and your container adapter will not operate properly until corrected.<BR><BR>
This is an error and your Acegi Security application will not operate properly until corrected.<BR><BR>
<% }
} else { %>
<B>ContextHolder on ContextHolder is null.</B><BR>
This indicates improper setup of the container adapter. Refer to the reference documentation.<BR>
Also ensure the correct subclass of AbstractMvcIntegrationInterceptor is being used for your container.<BR>
This indicates improper setup of the Acegi Security application. Refer to the reference documentation.<BR>
<%}
%>

View File

@ -2,54 +2,34 @@
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<!--
- Application context loaded by ContextLoaderListener if NOT using container adapters
- Application context containing authentication, channel
- security and web URI beans.
-
- Only used by "filter" artifact.
-
- $Id$
-->
<beans>
<!-- =================== SECURITY SYSTEM DEFINITIONS ================== -->
<!-- RunAsManager -->
<bean id="runAsManager" class="net.sf.acegisecurity.runas.RunAsManagerImpl">
<property name="key"><value>my_run_as_password</value></property>
</bean>
<!-- ~~~~~~~~~~~~~~~~~~~~ AUTHENTICATION DEFINITIONS ~~~~~~~~~~~~~~~~~~ -->
<bean id="runAsAuthenticationProvider" class="net.sf.acegisecurity.runas.RunAsImplAuthenticationProvider">
<property name="key"><value>my_run_as_password</value></property>
</bean>
<!-- ======================== AUTHENTICATION ======================= -->
<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref local="runAsAuthenticationProvider"/>
<ref local="daoAuthenticationProvider"/>
</list>
</property>
</bean>
<!-- Passwords encoded using MD5, NOT in Base64 format, with null as salt
Encoded password for marissa is "koala"
Encoded password for dianne is "emu"
Encoded password for scott is "wombat"
Encoded password for peter is "opal" -->
<bean id="inMemoryDaoImpl" class="net.sf.acegisecurity.providers.dao.memory.InMemoryDaoImpl">
<property name="userMap">
<value>
marissa=a564de63c2d0da68cf47586ee05984d7,ROLE_TELLER,ROLE_SUPERVISOR
dianne=65d15fe9156f9c4bbffd98085992a44e,ROLE_TELLER
scott=2b58af6dddbd072ed27ffc86725d7d3a,ROLE_TELLER
peter=22b5c9accc6e1ba628cedc63a72d57f8,disabled,ROLE_TELLER
</value>
</property>
<bean id="jdbcDaoImpl" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl">
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
<bean id="passwordEncoder" class="net.sf.acegisecurity.providers.encoding.Md5PasswordEncoder"/>
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="authenticationDao"><ref local="inMemoryDaoImpl"/></property>
<property name="authenticationDao"><ref local="jdbcDaoImpl"/></property>
<property name="userCache"><ref local="userCache"/></property>
<property name="passwordEncoder"><ref local="passwordEncoder"/></property>
</bean>
@ -70,85 +50,7 @@
<property name="realmName"><value>Contacts Realm</value></property>
</bean>
<bean id="autoIntegrationFilter" class="net.sf.acegisecurity.ui.AutoIntegrationFilter"/>
<!-- ~~~~~~~~~~~~~~~~~~~~ AUTHORIZATION DEFINITIONS ~~~~~~~~~~~~~~~~~~~ -->
<!-- An access decision voter that reads ROLE_* configuration settings -->
<bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/>
<!-- An access decision voter that reads CONTACT_OWNED_BY_CURRENT_USER configuration settings -->
<bean id="contactSecurityVoter" class="sample.contact.ContactSecurityVoter"/>
<!-- An access decision manager used by the business objects -->
<bean id="businessAccessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions"><value>false</value></property>
<property name="decisionVoters">
<list>
<ref local="roleVoter"/>
<ref local="contactSecurityVoter"/>
</list>
</property>
</bean>
<!-- ===================== SECURITY DEFINITIONS ======================= -->
<bean id="publicContactManagerSecurity" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager"><ref local="authenticationManager"/></property>
<property name="accessDecisionManager"><ref local="businessAccessDecisionManager"/></property>
<property name="runAsManager"><ref local="runAsManager"/></property>
<property name="objectDefinitionSource">
<value>
sample.contact.ContactManager.delete=ROLE_SUPERVISOR,RUN_AS_SERVER
sample.contact.ContactManager.getAllByOwner=CONTACT_OWNED_BY_CURRENT_USER,RUN_AS_SERVER
sample.contact.ContactManager.save=CONTACT_OWNED_BY_CURRENT_USER,RUN_AS_SERVER
sample.contact.ContactManager.getById=ROLE_TELLER,RUN_AS_SERVER
</value>
</property>
</bean>
<!-- We expect all callers of the backend object to hold the role ROLE_RUN_AS_SERVER -->
<bean id="backendContactManagerSecurity" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager"><ref local="authenticationManager"/></property>
<property name="accessDecisionManager"><ref local="businessAccessDecisionManager"/></property>
<property name="runAsManager"><ref local="runAsManager"/></property>
<property name="objectDefinitionSource">
<value>
sample.contact.ContactManager.delete=ROLE_RUN_AS_SERVER
sample.contact.ContactManager.getAllByOwner=ROLE_RUN_AS_SERVER
sample.contact.ContactManager.save=ROLE_RUN_AS_SERVER
sample.contact.ContactManager.getById=ROLE_RUN_AS_SERVER
</value>
</property>
</bean>
<!-- ======================= BUSINESS DEFINITIONS ===================== -->
<bean id="contactManager" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>sample.contact.ContactManager</value></property>
<property name="interceptorNames">
<list>
<idref local="publicContactManagerSecurity"/>
<idref local="publicContactManagerTarget"/>
</list>
</property>
</bean>
<bean id="publicContactManagerTarget" class="sample.contact.ContactManagerFacade">
<property name="backend"><ref local="backendContactManager"/></property>
</bean>
<bean id="backendContactManager" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>sample.contact.ContactManager</value></property>
<property name="interceptorNames">
<list>
<idref local="backendContactManagerSecurity"/>
<idref local="backendContactManagerTarget"/>
</list>
</property>
</bean>
<bean id="backendContactManagerTarget" class="sample.contact.ContactManagerBackend"/>
<bean id="httpSessionIntegrationFilter" class="net.sf.acegisecurity.ui.webapp.HttpSessionIntegrationFilter"/>
<!-- ===================== HTTP CHANNEL REQUIREMENTS ==================== -->
@ -182,18 +84,18 @@
<!-- ===================== HTTP REQUEST SECURITY ==================== -->
<bean id="authenticationProcessingFilter" class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
<property name="authenticationManager"><ref local="authenticationManager"/></property>
<property name="authenticationFailureUrl"><value>/acegilogin.jsp?login_error=1</value></property>
<property name="defaultTargetUrl"><value>/</value></property>
<property name="filterProcessesUrl"><value>/j_acegi_security_check</value></property>
</bean>
<bean id="securityEnforcementFilter" class="net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter">
<property name="filterSecurityInterceptor"><ref local="filterInvocationInterceptor"/></property>
<property name="authenticationEntryPoint"><ref local="authenticationProcessingFilterEntryPoint"/></property>
</bean>
<bean id="authenticationProcessingFilter" class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="authenticationFailureUrl"><value>/acegilogin.jsp?login_error=1</value></property>
<property name="defaultTargetUrl"><value>/</value></property>
<property name="filterProcessesUrl"><value>/j_acegi_security_check</value></property>
</bean>
<bean id="authenticationProcessingFilterEntryPoint" class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl"><value>/acegilogin.jsp</value></property>
<property name="forceHttps"><value>false</value></property>
@ -203,7 +105,7 @@
<property name="allowIfAllAbstainDecisions"><value>false</value></property>
<property name="decisionVoters">
<list>
<ref local="roleVoter"/>
<ref bean="roleVoter"/>
</list>
</property>
</bean>
@ -212,14 +114,13 @@
The FilterSecurityInterceptor will work from the top of the list down to the FIRST pattern that matches the request URL.
Accordingly, you should place MOST SPECIFIC (ie a/b/c/d.*) expressions first, with LEAST SPECIFIC (ie a/.*) expressions last -->
<bean id="filterInvocationInterceptor" class="net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager"><ref local="authenticationManager"/></property>
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="accessDecisionManager"><ref local="httpRequestAccessDecisionManager"/></property>
<property name="runAsManager"><ref local="runAsManager"/></property>
<property name="objectDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
\A/secure/super.*\Z=ROLE_WE_DONT_HAVE
\A/secure/.*\Z=ROLE_SUPERVISOR,ROLE_TELLER
\A/secure/.*\Z=ROLE_SUPERVISOR,ROLE_USER
</value>
</property>
</bean>

View File

@ -3,27 +3,35 @@
<!--
- Contacts web application
-
- web.xml for "filter" artifact only.
-
- $Id$
- File will be copied into WAR's WEB-INF directory if NOT using container adapter
-->
<web-app>
<display-name>Contacts Sample Application</display-name>
<description>
Example of an application secured using Acegi Security System for Spring.
</description>
<!--
- Location of the XML file that defines the root application context
- Applied by ContextLoaderListener.
-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
<param-value>
/WEB-INF/applicationContext-acegi-security.xml
/WEB-INF/applicationContext-common-business.xml
/WEB-INF/applicationContext-common-authorization.xml
</param-value>
</context-param>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/classes/log4j.properties</param-value>
</context-param>
<!-- The <filter-mapping> to this filter is disabled by default -->
<filter>
<filter-name>Acegi Channel Processing Filter</filter-name>
<filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
@ -33,6 +41,7 @@
</init-param>
</filter>
<!-- Responds to HTTP POSTs to j_acegi_security_check URI -->
<filter>
<filter-name>Acegi Authentication Processing Filter</filter-name>
<filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
@ -42,6 +51,7 @@
</init-param>
</filter>
<!-- Responds to HTTP requests with a BASIC (RFC 1945) authentication header -->
<filter>
<filter-name>Acegi HTTP BASIC Authorization Filter</filter-name>
<filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
@ -51,15 +61,21 @@
</init-param>
</filter>
<!-- Obtains Authentication from HttpSession attribute, puts it into
ContextHolder for request duration, proceeds with request, then
copies Authentication from ContextHolder back into HttpSession -->
<filter>
<filter-name>Acegi Security System for Spring Auto Integration Filter</filter-name>
<filter-name>Acegi Security System for Spring HttpSession Integration Filter</filter-name>
<filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>net.sf.acegisecurity.ui.AutoIntegrationFilter</param-value>
<param-value>net.sf.acegisecurity.ui.webapp.HttpSessionIntegrationFilter</param-value>
</init-param>
</filter>
<!-- Provides HTTP request URL security, and also catches
AcegiSecurityExceptions and sends 403 errors (if access denied)
or commences an authentication mechanism as appropriate -->
<filter>
<filter-name>Acegi HTTP Request Security Filter</filter-name>
<filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
@ -89,7 +105,7 @@
</filter-mapping>
<filter-mapping>
<filter-name>Acegi Security System for Spring Auto Integration Filter</filter-name>
<filter-name>Acegi Security System for Spring HttpSession Integration Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
@ -99,23 +115,20 @@
</filter-mapping>
<!--
- Loads the root application context of this web app at startup,
- by default from "/WEB-INF/applicationContext.xml".
- Use WebApplicationContextUtils.getWebApplicationContext(servletContext)
- to access it anywhere in the web application, outside of the framework.
- Loads the root application context of this web app at startup.
- The application context is then available via
- WebApplicationContextUtils.getWebApplicationContext(servletContext).
-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<!--
- Servlet that dispatches request to registered handlers (Controller implementations).
- Has its own application context, by default defined in "{servlet-name}-servlet.xml",
- i.e. "contacts-servlet.xml".
-
- A web app can contain any number of such servlets.
- Note that this web app does not have a shared root application context,
- therefore the DispatcherServlet contexts do not have a common parent.
- Provides core MVC application controller. See contacts-servlet.xml.
-->
<servlet>
<servlet-name>contacts</servlet-name>
@ -123,25 +136,20 @@
<load-on-startup>1</load-on-startup>
</servlet>
<!--
- Provides web services endpoint. See caucho-servlet.xml.
-->
<servlet>
<servlet-name>caucho</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<!--
- Maps the contacts dispatcher to /*.
-
-->
<servlet-mapping>
<servlet-name>contacts</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<!--
- Dispatcher servlet mapping for HTTP remoting via the Caucho protocols,
- i.e. Hessian and Burlap (see caucho-servlet.xml for the controllers).
-->
<servlet-mapping>
<servlet-name>caucho</servlet-name>
<url-pattern>/caucho/*</url-pattern>
@ -155,5 +163,5 @@
<taglib-uri>/spring</taglib-uri>
<taglib-location>/WEB-INF/spring.tld</taglib-location>
</taglib>
</web-app>

View File

@ -1,7 +1,6 @@
<%@ taglib prefix='c' uri='http://java.sun.com/jstl/core' %>
<%@ page import="net.sf.acegisecurity.ui.AbstractProcessingFilter" %>
<%@ page import="net.sf.acegisecurity.AuthenticationException" %>
<%-- This page will be copied into WAR's root directory if NOT using container adapter --%>
<html>
<head>
@ -11,11 +10,12 @@
<body>
<h1>Login</h1>
<P>If you've used the standard springsecurity.xml, try these users:
<P>Valid users:
<P>
<P>username <b>marissa</b>, password <b>koala</b> (granted ROLE_SUPERVISOR)
<P>username <b>dianne</b>, password <b>emu</b> (not a supervisor)
<p>username <b>scott</b>, password <b>wombat</b> (not a supervisor)
<P>username <b>marissa</b>, password <b>koala</b>
<P>username <b>dianne</b>, password <b>emu</b>
<p>username <b>scott</b>, password <b>wombat</b>
<p>username <b>peter</b>, password <b>opal</b> (user disabled)
<p>
<%-- this form-login-page form is also used as the