Use xml / javaconfig folders for samples
Fixes gh-3752
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* 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.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
*/
|
||||
@Controller
|
||||
public class AddDeleteContactController {
|
||||
@Autowired
|
||||
private ContactManager contactManager;
|
||||
private final Validator validator = new WebContactValidator();
|
||||
|
||||
/**
|
||||
* Displays the "add contact" form.
|
||||
*/
|
||||
@RequestMapping(value = "/secure/add.htm", method = RequestMethod.GET)
|
||||
public ModelAndView addContactDisplay() {
|
||||
return new ModelAndView("add", "webContact", new WebContact());
|
||||
}
|
||||
|
||||
@InitBinder
|
||||
public void initBinder(WebDataBinder binder) {
|
||||
System.out.println("A binder for object: " + binder.getObjectName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the submission of the contact form, creating a new instance if the username
|
||||
* and email are valid.
|
||||
*/
|
||||
@RequestMapping(value = "/secure/add.htm", method = RequestMethod.POST)
|
||||
public String addContact(WebContact form, BindingResult result) {
|
||||
validator.validate(form, result);
|
||||
|
||||
if (result.hasErrors()) {
|
||||
return "add";
|
||||
}
|
||||
|
||||
Contact contact = new Contact(form.getName(), form.getEmail());
|
||||
contactManager.create(contact);
|
||||
|
||||
return "redirect:/secure/index.htm";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/secure/del.htm", method = RequestMethod.GET)
|
||||
public ModelAndView handleRequest(@RequestParam("contactId") int contactId) {
|
||||
Contact contact = contactManager.getById(Long.valueOf(contactId));
|
||||
contactManager.delete(contact);
|
||||
|
||||
return new ModelAndView("deleted", "contact", contact);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 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.security.acls.domain.BasePermission;
|
||||
|
||||
/**
|
||||
* Model object for add permission use case.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class AddPermission {
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
public Contact contact;
|
||||
public Integer permission = BasePermission.READ.getMask();
|
||||
public String recipient;
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public Contact getContact() {
|
||||
return contact;
|
||||
}
|
||||
|
||||
public Integer getPermission() {
|
||||
return permission;
|
||||
}
|
||||
|
||||
public String getRecipient() {
|
||||
return recipient;
|
||||
}
|
||||
|
||||
public void setContact(Contact contact) {
|
||||
this.contact = contact;
|
||||
}
|
||||
|
||||
public void setPermission(Integer permission) {
|
||||
this.permission = permission;
|
||||
}
|
||||
|
||||
public void setRecipient(String recipient) {
|
||||
this.recipient = recipient;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 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.security.acls.domain.BasePermission;
|
||||
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.ValidationUtils;
|
||||
import org.springframework.validation.Validator;
|
||||
|
||||
/**
|
||||
* Validates {@link AddPermission}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class AddPermissionValidator implements Validator {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
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 != BasePermission.ADMINISTRATION.getMask())
|
||||
&& (permission != BasePermission.READ.getMask())
|
||||
&& (permission != BasePermission.DELETE.getMask())) {
|
||||
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). *");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* 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.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceAware;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.domain.DefaultPermissionFactory;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.domain.PermissionFactory;
|
||||
import org.springframework.security.acls.domain.PrincipalSid;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.AclService;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.SessionAttributes;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
* Web controller to handle <tt>Permission</tt> administration functions - adding and
|
||||
* deleting permissions for contacts.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
*/
|
||||
@Controller
|
||||
@SessionAttributes("addPermission")
|
||||
public final class AdminPermissionController implements MessageSourceAware {
|
||||
@Autowired
|
||||
private AclService aclService;
|
||||
@Autowired
|
||||
private ContactManager contactManager;
|
||||
private MessageSourceAccessor messages;
|
||||
private final Validator addPermissionValidator = new AddPermissionValidator();
|
||||
private final PermissionFactory permissionFactory = new DefaultPermissionFactory();
|
||||
|
||||
/**
|
||||
* Displays the permission admin page for a particular contact.
|
||||
*/
|
||||
@RequestMapping(value = "/secure/adminPermission.htm", method = RequestMethod.GET)
|
||||
public ModelAndView displayAdminPage(@RequestParam("contactId") int contactId) {
|
||||
Contact contact = contactManager.getById(Long.valueOf(contactId));
|
||||
Acl acl = aclService.readAclById(new ObjectIdentityImpl(contact));
|
||||
|
||||
Map<String, Object> model = new HashMap<String, Object>();
|
||||
model.put("contact", contact);
|
||||
model.put("acl", acl);
|
||||
|
||||
return new ModelAndView("adminPermission", "model", model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the "add permission" page for a contact.
|
||||
*/
|
||||
@RequestMapping(value = "/secure/addPermission.htm", method = RequestMethod.GET)
|
||||
public ModelAndView displayAddPermissionPageForContact(
|
||||
@RequestParam("contactId") int contactId) {
|
||||
Contact contact = contactManager.getById(new Long(contactId));
|
||||
|
||||
AddPermission addPermission = new AddPermission();
|
||||
addPermission.setContact(contact);
|
||||
|
||||
Map<String, Object> model = new HashMap<String, Object>();
|
||||
model.put("addPermission", addPermission);
|
||||
model.put("recipients", listRecipients());
|
||||
model.put("permissions", listPermissions());
|
||||
|
||||
return new ModelAndView("addPermission", model);
|
||||
}
|
||||
|
||||
@InitBinder("addPermission")
|
||||
public void initBinder(WebDataBinder binder) {
|
||||
binder.setAllowedFields("recipient", "permission");
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles submission of the "add permission" form.
|
||||
*/
|
||||
@RequestMapping(value = "/secure/addPermission.htm", method = RequestMethod.POST)
|
||||
public String addPermission(AddPermission addPermission, BindingResult result,
|
||||
ModelMap model) {
|
||||
addPermissionValidator.validate(addPermission, result);
|
||||
|
||||
if (result.hasErrors()) {
|
||||
model.put("recipients", listRecipients());
|
||||
model.put("permissions", listPermissions());
|
||||
|
||||
return "addPermission";
|
||||
}
|
||||
|
||||
PrincipalSid sid = new PrincipalSid(addPermission.getRecipient());
|
||||
Permission permission = permissionFactory.buildFromMask(addPermission
|
||||
.getPermission());
|
||||
|
||||
try {
|
||||
contactManager.addPermission(addPermission.getContact(), sid, permission);
|
||||
}
|
||||
catch (DataAccessException existingPermission) {
|
||||
existingPermission.printStackTrace();
|
||||
result.rejectValue("recipient", "err.recipientExistsForContact",
|
||||
"Addition failure.");
|
||||
|
||||
model.put("recipients", listRecipients());
|
||||
model.put("permissions", listPermissions());
|
||||
return "addPermission";
|
||||
}
|
||||
|
||||
return "redirect:/secure/index.htm";
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a permission
|
||||
*/
|
||||
@RequestMapping(value = "/secure/deletePermission.htm")
|
||||
public ModelAndView deletePermission(@RequestParam("contactId") int contactId,
|
||||
@RequestParam("sid") String sid, @RequestParam("permission") int mask) {
|
||||
|
||||
Contact contact = contactManager.getById(new Long(contactId));
|
||||
|
||||
Sid sidObject = new PrincipalSid(sid);
|
||||
Permission permission = permissionFactory.buildFromMask(mask);
|
||||
|
||||
contactManager.deletePermission(contact, sidObject, permission);
|
||||
|
||||
Map<String, Object> model = new HashMap<String, Object>();
|
||||
model.put("contact", contact);
|
||||
model.put("sid", sidObject);
|
||||
model.put("permission", permission);
|
||||
|
||||
return new ModelAndView("deletePermission", "model", model);
|
||||
}
|
||||
|
||||
private Map<Integer, String> listPermissions() {
|
||||
Map<Integer, String> map = new LinkedHashMap<Integer, String>();
|
||||
map.put(Integer.valueOf(BasePermission.ADMINISTRATION.getMask()),
|
||||
messages.getMessage("select.administer", "Administer"));
|
||||
map.put(Integer.valueOf(BasePermission.READ.getMask()),
|
||||
messages.getMessage("select.read", "Read"));
|
||||
map.put(Integer.valueOf(BasePermission.DELETE.getMask()),
|
||||
messages.getMessage("select.delete", "Delete"));
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private Map<String, String> listRecipients() {
|
||||
Map<String, String> map = new LinkedHashMap<String, String>();
|
||||
map.put("", messages.getMessage("select.pleaseSelect", "-- please select --"));
|
||||
|
||||
for (String recipient : contactManager.getAllRecipients()) {
|
||||
map.put(recipient, recipient);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
public void setMessageSource(MessageSource messageSource) {
|
||||
this.messages = new MessageSourceAccessor(messageSource);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 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.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.context.support.FileSystemXmlApplicationContext;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.util.StopWatch;
|
||||
|
||||
/**
|
||||
* Demonstrates accessing the {@link ContactManager} via remoting protocols.
|
||||
* <p>
|
||||
* Based on Spring's JPetStore sample, written by Juergen Hoeller.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class ClientApplication {
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private final ListableBeanFactory beanFactory;
|
||||
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
public ClientApplication(ListableBeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public void invokeContactManager(Authentication authentication, int nrOfCalls) {
|
||||
StopWatch stopWatch = new StopWatch(nrOfCalls + " ContactManager call(s)");
|
||||
Map<String, ContactManager> contactServices = this.beanFactory.getBeansOfType(
|
||||
ContactManager.class, true, true);
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
|
||||
for (String beanName : contactServices.keySet()) {
|
||||
Object object = this.beanFactory.getBean("&" + beanName);
|
||||
|
||||
try {
|
||||
System.out.println("Trying to find setUsername(String) method on: "
|
||||
+ object.getClass().getName());
|
||||
|
||||
Method method = object.getClass().getMethod("setUsername",
|
||||
new Class[] { String.class });
|
||||
System.out.println("Found; Trying to setUsername(String) to "
|
||||
+ authentication.getPrincipal());
|
||||
method.invoke(object, authentication.getPrincipal());
|
||||
}
|
||||
catch (NoSuchMethodException ignored) {
|
||||
System.out
|
||||
.println("This client proxy factory does not have a setUsername(String) method");
|
||||
}
|
||||
catch (IllegalAccessException ignored) {
|
||||
ignored.printStackTrace();
|
||||
}
|
||||
catch (InvocationTargetException ignored) {
|
||||
ignored.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
System.out.println("Trying to find setPassword(String) method on: "
|
||||
+ object.getClass().getName());
|
||||
|
||||
Method method = object.getClass().getMethod("setPassword",
|
||||
new Class[] { String.class });
|
||||
method.invoke(object, authentication.getCredentials());
|
||||
System.out.println("Found; Trying to setPassword(String) to "
|
||||
+ authentication.getCredentials());
|
||||
}
|
||||
catch (NoSuchMethodException ignored) {
|
||||
System.out
|
||||
.println("This client proxy factory does not have a setPassword(String) method");
|
||||
}
|
||||
catch (IllegalAccessException ignored) {
|
||||
}
|
||||
catch (InvocationTargetException ignored) {
|
||||
}
|
||||
|
||||
ContactManager remoteContactManager = contactServices.get(beanName);
|
||||
System.out.println("Calling ContactManager '" + beanName + "'");
|
||||
|
||||
stopWatch.start(beanName);
|
||||
|
||||
List<Contact> contacts = null;
|
||||
|
||||
for (int i = 0; i < nrOfCalls; i++) {
|
||||
contacts = remoteContactManager.getAll();
|
||||
}
|
||||
|
||||
stopWatch.stop();
|
||||
|
||||
if (contacts.size() != 0) {
|
||||
for (Contact contact : contacts) {
|
||||
System.out.println("Contact: " + contact);
|
||||
}
|
||||
}
|
||||
else {
|
||||
System.out.println("No contacts found which this user has permission to");
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
System.out.println(stopWatch.prettyPrint());
|
||||
}
|
||||
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String username = System.getProperty("username", "");
|
||||
String password = System.getProperty("password", "");
|
||||
String nrOfCallsString = System.getProperty("nrOfCalls", "");
|
||||
|
||||
if ("".equals(username) || "".equals(password)) {
|
||||
System.out
|
||||
.println("You need to specify the user ID to use, the password to use, and optionally a number of calls "
|
||||
+ "using the username, password, and nrOfCalls system properties respectively. eg for user rod, "
|
||||
+ "use: -Dusername=rod -Dpassword=koala' for a single call per service and "
|
||||
+ "use: -Dusername=rod -Dpassword=koala -DnrOfCalls=10 for ten calls per service.");
|
||||
System.exit(-1);
|
||||
}
|
||||
else {
|
||||
int nrOfCalls = 1;
|
||||
|
||||
if (!"".equals(nrOfCallsString)) {
|
||||
nrOfCalls = Integer.parseInt(nrOfCallsString);
|
||||
}
|
||||
|
||||
ListableBeanFactory beanFactory = new FileSystemXmlApplicationContext(
|
||||
"clientContext.xml");
|
||||
ClientApplication client = new ClientApplication(beanFactory);
|
||||
|
||||
client.invokeContactManager(new UsernamePasswordAuthenticationToken(username,
|
||||
password), nrOfCalls);
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 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.io.Serializable;
|
||||
|
||||
/**
|
||||
* Represents a contact.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class Contact implements Serializable {
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private Long id;
|
||||
private String email;
|
||||
private String name;
|
||||
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
public Contact(String name, String email) {
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public Contact() {
|
||||
}
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
/**
|
||||
* @return Returns the email.
|
||||
*/
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the id.
|
||||
*/
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param email The email to set.
|
||||
*/
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name The name to set.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(super.toString() + ": ");
|
||||
sb.append("Id: " + this.getId() + "; ");
|
||||
sb.append("Name: " + this.getName() + "; ");
|
||||
sb.append("Email: " + this.getEmail());
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 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
|
||||
*/
|
||||
public interface ContactDao {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public void create(Contact contact);
|
||||
|
||||
public void delete(Long contactId);
|
||||
|
||||
public List<Contact> findAll();
|
||||
|
||||
public List<String> findAllPrincipals();
|
||||
|
||||
public List<String> findAllRoles();
|
||||
|
||||
public Contact getById(Long id);
|
||||
|
||||
public void update(Contact contact);
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 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.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.jdbc.core.PreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.core.support.JdbcDaoSupport;
|
||||
|
||||
/**
|
||||
* Base implementation of {@link ContactDao} that uses Spring's JdbcTemplate.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class ContactDaoSpring extends JdbcDaoSupport implements ContactDao {
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public void create(final Contact contact) {
|
||||
getJdbcTemplate().update("insert into contacts values (?, ?, ?)",
|
||||
new PreparedStatementSetter() {
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
ps.setLong(1, contact.getId());
|
||||
ps.setString(2, contact.getName());
|
||||
ps.setString(3, contact.getEmail());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void delete(final Long contactId) {
|
||||
getJdbcTemplate().update("delete from contacts where id = ?",
|
||||
new PreparedStatementSetter() {
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
ps.setLong(1, contactId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void update(final Contact contact) {
|
||||
getJdbcTemplate().update(
|
||||
"update contacts set contact_name = ?, address = ? where id = ?",
|
||||
new PreparedStatementSetter() {
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
ps.setString(1, contact.getName());
|
||||
ps.setString(2, contact.getEmail());
|
||||
ps.setLong(3, contact.getId());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public List<Contact> findAll() {
|
||||
return getJdbcTemplate().query(
|
||||
"select id, contact_name, email from contacts order by id",
|
||||
new RowMapper<Contact>() {
|
||||
public Contact mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return mapContact(rs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public List<String> findAllPrincipals() {
|
||||
return getJdbcTemplate().queryForList(
|
||||
"select username from users order by username", String.class);
|
||||
}
|
||||
|
||||
public List<String> findAllRoles() {
|
||||
return getJdbcTemplate().queryForList(
|
||||
"select distinct authority from authorities order by authority",
|
||||
String.class);
|
||||
}
|
||||
|
||||
public Contact getById(Long id) {
|
||||
List<Contact> list = getJdbcTemplate().query(
|
||||
"select id, contact_name, email from contacts where id = ? order by id",
|
||||
new RowMapper<Contact>() {
|
||||
public Contact mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return mapContact(rs);
|
||||
}
|
||||
}, id);
|
||||
|
||||
if (list.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return (Contact) list.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
private Contact mapContact(ResultSet rs) throws SQLException {
|
||||
Contact contact = new Contact();
|
||||
contact.setId(new Long(rs.getLong("id")));
|
||||
contact.setName(rs.getString("contact_name"));
|
||||
contact.setEmail(rs.getString("email"));
|
||||
|
||||
return contact;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 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.security.access.prepost.PostFilter;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Interface for the application's services layer.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface ContactManager {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
@PreAuthorize("hasPermission(#contact, admin)")
|
||||
public void addPermission(Contact contact, Sid recipient, Permission permission);
|
||||
|
||||
@PreAuthorize("hasPermission(#contact, admin)")
|
||||
public void deletePermission(Contact contact, Sid recipient, Permission permission);
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_USER')")
|
||||
public void create(Contact contact);
|
||||
|
||||
@PreAuthorize("hasPermission(#contact, 'delete') or hasPermission(#contact, admin)")
|
||||
public void delete(Contact contact);
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_USER')")
|
||||
@PostFilter("hasPermission(filterObject, 'read') or hasPermission(filterObject, admin)")
|
||||
public List<Contact> getAll();
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_USER')")
|
||||
public List<String> getAllRecipients();
|
||||
|
||||
@PreAuthorize("hasPermission(#id, 'sample.contact.Contact', read) or "
|
||||
+ "hasPermission(#id, 'sample.contact.Contact', admin)")
|
||||
public Contact getById(Long id);
|
||||
|
||||
public Contact getRandomContact();
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 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.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.domain.PrincipalSid;
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
import org.springframework.security.acls.model.MutableAcl;
|
||||
import org.springframework.security.acls.model.MutableAclService;
|
||||
import org.springframework.security.acls.model.NotFoundException;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import org.springframework.context.support.ApplicationObjectSupport;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Concrete implementation of {@link ContactManager}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
@Transactional
|
||||
public class ContactManagerBackend extends ApplicationObjectSupport implements
|
||||
ContactManager, InitializingBean {
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private ContactDao contactDao;
|
||||
private MutableAclService mutableAclService;
|
||||
private int counter = 1000;
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(contactDao, "contactDao required");
|
||||
Assert.notNull(mutableAclService, "mutableAclService required");
|
||||
}
|
||||
|
||||
public void addPermission(Contact contact, Sid recipient, Permission permission) {
|
||||
MutableAcl acl;
|
||||
ObjectIdentity oid = new ObjectIdentityImpl(Contact.class, contact.getId());
|
||||
|
||||
try {
|
||||
acl = (MutableAcl) mutableAclService.readAclById(oid);
|
||||
}
|
||||
catch (NotFoundException nfe) {
|
||||
acl = mutableAclService.createAcl(oid);
|
||||
}
|
||||
|
||||
acl.insertAce(acl.getEntries().size(), permission, recipient, true);
|
||||
mutableAclService.updateAcl(acl);
|
||||
|
||||
logger.debug("Added permission " + permission + " for Sid " + recipient
|
||||
+ " contact " + contact);
|
||||
}
|
||||
|
||||
public void create(Contact contact) {
|
||||
// Create the Contact itself
|
||||
contact.setId(new Long(counter++));
|
||||
contactDao.create(contact);
|
||||
|
||||
// Grant the current principal administrative permission to the contact
|
||||
addPermission(contact, new PrincipalSid(getUsername()),
|
||||
BasePermission.ADMINISTRATION);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Created contact " + contact
|
||||
+ " and granted admin permission to recipient " + getUsername());
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(Contact contact) {
|
||||
contactDao.delete(contact.getId());
|
||||
|
||||
// Delete the ACL information as well
|
||||
ObjectIdentity oid = new ObjectIdentityImpl(Contact.class, contact.getId());
|
||||
mutableAclService.deleteAcl(oid, false);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Deleted contact " + contact + " including ACL permissions");
|
||||
}
|
||||
}
|
||||
|
||||
public void deletePermission(Contact contact, Sid recipient, Permission permission) {
|
||||
ObjectIdentity oid = new ObjectIdentityImpl(Contact.class, contact.getId());
|
||||
MutableAcl acl = (MutableAcl) mutableAclService.readAclById(oid);
|
||||
|
||||
// Remove all permissions associated with this particular recipient (string
|
||||
// equality to KISS)
|
||||
List<AccessControlEntry> entries = acl.getEntries();
|
||||
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
if (entries.get(i).getSid().equals(recipient)
|
||||
&& entries.get(i).getPermission().equals(permission)) {
|
||||
acl.deleteAce(i);
|
||||
}
|
||||
}
|
||||
|
||||
mutableAclService.updateAcl(acl);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Deleted contact " + contact + " ACL permissions for recipient "
|
||||
+ recipient);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<Contact> getAll() {
|
||||
logger.debug("Returning all contacts");
|
||||
|
||||
return contactDao.findAll();
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<String> getAllRecipients() {
|
||||
logger.debug("Returning all recipients");
|
||||
|
||||
return contactDao.findAllPrincipals();
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Contact getById(Long id) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Returning contact with id: " + id);
|
||||
}
|
||||
|
||||
return contactDao.getById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a public method.
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public Contact getRandomContact() {
|
||||
logger.debug("Returning random contact");
|
||||
|
||||
Random rnd = new Random();
|
||||
List<Contact> contacts = contactDao.findAll();
|
||||
int getNumber = rnd.nextInt(contacts.size());
|
||||
|
||||
return contacts.get(getNumber);
|
||||
}
|
||||
|
||||
protected String getUsername() {
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
if (auth.getPrincipal() instanceof UserDetails) {
|
||||
return ((UserDetails) auth.getPrincipal()).getUsername();
|
||||
}
|
||||
else {
|
||||
return auth.getPrincipal().toString();
|
||||
}
|
||||
}
|
||||
|
||||
public void setContactDao(ContactDao contactDao) {
|
||||
this.contactDao = contactDao;
|
||||
}
|
||||
|
||||
public void setMutableAclService(MutableAclService mutableAclService) {
|
||||
this.mutableAclService = mutableAclService;
|
||||
}
|
||||
|
||||
public void update(Contact contact) {
|
||||
contactDao.update(contact);
|
||||
|
||||
logger.debug("Updated contact " + contact);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 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.Random;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.security.acls.domain.AclImpl;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.domain.PrincipalSid;
|
||||
import org.springframework.security.acls.model.MutableAcl;
|
||||
import org.springframework.security.acls.model.MutableAclService;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionCallback;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Populates the Contacts in-memory database with contact and ACL information.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class DataSourcePopulator implements InitializingBean {
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
JdbcTemplate template;
|
||||
private MutableAclService mutableAclService;
|
||||
final Random rnd = new Random();
|
||||
TransactionTemplate tt;
|
||||
final String[] firstNames = { "Bob", "Mary", "James", "Jane", "Kristy", "Kirsty",
|
||||
"Kate", "Jeni", "Angela", "Melanie", "Kent", "William", "Geoff", "Jeff",
|
||||
"Adrian", "Amanda", "Lisa", "Elizabeth", "Prue", "Richard", "Darin",
|
||||
"Phillip", "Michael", "Belinda", "Samantha", "Brian", "Greg", "Matthew" };
|
||||
final String[] lastNames = { "Smith", "Williams", "Jackson", "Rictor", "Nelson",
|
||||
"Fitzgerald", "McAlpine", "Sutherland", "Abbott", "Hall", "Edwards", "Gates",
|
||||
"Black", "Brown", "Gray", "Marwell", "Booch", "Johnson", "McTaggart",
|
||||
"Parklin", "Findlay", "Robinson", "Giugni", "Lang", "Chi", "Carmichael" };
|
||||
private int createEntities = 50;
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(mutableAclService, "mutableAclService required");
|
||||
Assert.notNull(template, "dataSource required");
|
||||
Assert.notNull(tt, "platformTransactionManager required");
|
||||
|
||||
// Set a user account that will initially own all the created data
|
||||
Authentication authRequest = new UsernamePasswordAuthenticationToken("rod",
|
||||
"koala", AuthorityUtils.createAuthorityList("ROLE_IGNORED"));
|
||||
SecurityContextHolder.getContext().setAuthentication(authRequest);
|
||||
|
||||
try {
|
||||
template.execute("DROP TABLE CONTACTS");
|
||||
template.execute("DROP TABLE AUTHORITIES");
|
||||
template.execute("DROP TABLE USERS");
|
||||
template.execute("DROP TABLE ACL_ENTRY");
|
||||
template.execute("DROP TABLE ACL_OBJECT_IDENTITY");
|
||||
template.execute("DROP TABLE ACL_CLASS");
|
||||
template.execute("DROP TABLE ACL_SID");
|
||||
}
|
||||
catch (Exception e) {
|
||||
System.out.println("Failed to drop tables: " + e.getMessage());
|
||||
}
|
||||
|
||||
template.execute("CREATE TABLE ACL_SID("
|
||||
+ "ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,"
|
||||
+ "PRINCIPAL BOOLEAN NOT NULL," + "SID VARCHAR_IGNORECASE(100) NOT NULL,"
|
||||
+ "CONSTRAINT UNIQUE_UK_1 UNIQUE(SID,PRINCIPAL));");
|
||||
template.execute("CREATE TABLE ACL_CLASS("
|
||||
+ "ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,"
|
||||
+ "CLASS VARCHAR_IGNORECASE(100) NOT NULL,"
|
||||
+ "CONSTRAINT UNIQUE_UK_2 UNIQUE(CLASS));");
|
||||
template.execute("CREATE TABLE ACL_OBJECT_IDENTITY("
|
||||
+ "ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,"
|
||||
+ "OBJECT_ID_CLASS BIGINT NOT NULL,"
|
||||
+ "OBJECT_ID_IDENTITY BIGINT NOT NULL,"
|
||||
+ "PARENT_OBJECT BIGINT,"
|
||||
+ "OWNER_SID BIGINT,"
|
||||
+ "ENTRIES_INHERITING BOOLEAN NOT NULL,"
|
||||
+ "CONSTRAINT UNIQUE_UK_3 UNIQUE(OBJECT_ID_CLASS,OBJECT_ID_IDENTITY),"
|
||||
+ "CONSTRAINT FOREIGN_FK_1 FOREIGN KEY(PARENT_OBJECT)REFERENCES ACL_OBJECT_IDENTITY(ID),"
|
||||
+ "CONSTRAINT FOREIGN_FK_2 FOREIGN KEY(OBJECT_ID_CLASS)REFERENCES ACL_CLASS(ID),"
|
||||
+ "CONSTRAINT FOREIGN_FK_3 FOREIGN KEY(OWNER_SID)REFERENCES ACL_SID(ID));");
|
||||
template.execute("CREATE TABLE ACL_ENTRY("
|
||||
+ "ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,"
|
||||
+ "ACL_OBJECT_IDENTITY BIGINT NOT NULL,ACE_ORDER INT NOT NULL,SID BIGINT NOT NULL,"
|
||||
+ "MASK INTEGER NOT NULL,GRANTING BOOLEAN NOT NULL,AUDIT_SUCCESS BOOLEAN NOT NULL,"
|
||||
+ "AUDIT_FAILURE BOOLEAN NOT NULL,CONSTRAINT UNIQUE_UK_4 UNIQUE(ACL_OBJECT_IDENTITY,ACE_ORDER),"
|
||||
+ "CONSTRAINT FOREIGN_FK_4 FOREIGN KEY(ACL_OBJECT_IDENTITY) REFERENCES ACL_OBJECT_IDENTITY(ID),"
|
||||
+ "CONSTRAINT FOREIGN_FK_5 FOREIGN KEY(SID) REFERENCES ACL_SID(ID));");
|
||||
|
||||
template.execute("CREATE TABLE USERS(USERNAME VARCHAR_IGNORECASE(50) NOT NULL PRIMARY KEY,PASSWORD VARCHAR_IGNORECASE(500) 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);");
|
||||
|
||||
template.execute("CREATE TABLE CONTACTS(ID BIGINT NOT NULL PRIMARY KEY, CONTACT_NAME VARCHAR_IGNORECASE(50) NOT NULL, EMAIL VARCHAR_IGNORECASE(50) NOT NULL)");
|
||||
|
||||
/*
|
||||
* Passwords encoded using MD5, NOT in Base64 format, with null as salt Encoded
|
||||
* password for rod is "koala" Encoded password for dianne is "emu" Encoded
|
||||
* password for scott is "wombat" Encoded password for peter is "opal" (but user
|
||||
* is disabled) Encoded password for bill is "wombat" Encoded password for bob is
|
||||
* "wombat" Encoded password for jane is "wombat"
|
||||
*/
|
||||
template.execute("INSERT INTO USERS VALUES('rod','$2a$10$75pBjapg4Nl8Pzd.3JRnUe7PDJmk9qBGwNEJDAlA3V.dEJxcDKn5O',TRUE);");
|
||||
template.execute("INSERT INTO USERS VALUES('dianne','$2a$04$bCMEyxrdF/7sgfUiUJ6Ose2vh9DAMaVBldS1Bw2fhi1jgutZrr9zm',TRUE);");
|
||||
template.execute("INSERT INTO USERS VALUES('scott','$2a$06$eChwvzAu3TSexnC3ynw4LOSw1qiEbtNItNeYv5uI40w1i3paoSfLu',TRUE);");
|
||||
template.execute("INSERT INTO USERS VALUES('peter','$2a$04$8.H8bCMROLF4CIgd7IpeQ.tcBXLP5w8iplO0n.kCIkISwrIgX28Ii',FALSE);");
|
||||
template.execute("INSERT INTO USERS VALUES('bill','$2a$04$8.H8bCMROLF4CIgd7IpeQ.3khQlPVNWbp8kzSQqidQHGFurim7P8O',TRUE);");
|
||||
template.execute("INSERT INTO USERS VALUES('bob','$2a$06$zMgxlMf01SfYNcdx7n4NpeFlAGU8apCETz/i2C7VlYWu6IcNyn4Ay',TRUE);");
|
||||
template.execute("INSERT INTO USERS VALUES('jane','$2a$05$ZrdS7yMhCZ1J.AAidXZhCOxdjD8LO/dhlv4FJzkXA6xh9gdEbBT/u',TRUE);");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('rod','ROLE_USER');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('rod','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');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('bill','ROLE_USER');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('bob','ROLE_USER');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('jane','ROLE_USER');");
|
||||
|
||||
template.execute("INSERT INTO contacts VALUES (1, 'John Smith', 'john@somewhere.com');");
|
||||
template.execute("INSERT INTO contacts VALUES (2, 'Michael Citizen', 'michael@xyz.com');");
|
||||
template.execute("INSERT INTO contacts VALUES (3, 'Joe Bloggs', 'joe@demo.com');");
|
||||
template.execute("INSERT INTO contacts VALUES (4, 'Karen Sutherland', 'karen@sutherland.com');");
|
||||
template.execute("INSERT INTO contacts VALUES (5, 'Mitchell Howard', 'mitchell@abcdef.com');");
|
||||
template.execute("INSERT INTO contacts VALUES (6, 'Rose Costas', 'rose@xyz.com');");
|
||||
template.execute("INSERT INTO contacts VALUES (7, 'Amanda Smith', 'amanda@abcdef.com');");
|
||||
template.execute("INSERT INTO contacts VALUES (8, 'Cindy Smith', 'cindy@smith.com');");
|
||||
template.execute("INSERT INTO contacts VALUES (9, 'Jonathan Citizen', 'jonathan@xyz.com');");
|
||||
|
||||
for (int i = 10; i < createEntities; i++) {
|
||||
String[] person = selectPerson();
|
||||
template.execute("INSERT INTO contacts VALUES (" + i + ", '" + person[2]
|
||||
+ "', '" + person[0].toLowerCase() + "@" + person[1].toLowerCase()
|
||||
+ ".com');");
|
||||
}
|
||||
|
||||
// Create acl_object_identity rows (and also acl_class rows as needed
|
||||
for (int i = 1; i < createEntities; i++) {
|
||||
final ObjectIdentity objectIdentity = new ObjectIdentityImpl(Contact.class,
|
||||
new Long(i));
|
||||
tt.execute(new TransactionCallback<Object>() {
|
||||
public Object doInTransaction(TransactionStatus arg0) {
|
||||
mutableAclService.createAcl(objectIdentity);
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Now grant some permissions
|
||||
grantPermissions(1, "rod", BasePermission.ADMINISTRATION);
|
||||
grantPermissions(2, "rod", BasePermission.READ);
|
||||
grantPermissions(3, "rod", BasePermission.READ);
|
||||
grantPermissions(3, "rod", BasePermission.WRITE);
|
||||
grantPermissions(3, "rod", BasePermission.DELETE);
|
||||
grantPermissions(4, "rod", BasePermission.ADMINISTRATION);
|
||||
grantPermissions(4, "dianne", BasePermission.ADMINISTRATION);
|
||||
grantPermissions(4, "scott", BasePermission.READ);
|
||||
grantPermissions(5, "dianne", BasePermission.ADMINISTRATION);
|
||||
grantPermissions(5, "dianne", BasePermission.READ);
|
||||
grantPermissions(6, "dianne", BasePermission.READ);
|
||||
grantPermissions(6, "dianne", BasePermission.WRITE);
|
||||
grantPermissions(6, "dianne", BasePermission.DELETE);
|
||||
grantPermissions(6, "scott", BasePermission.READ);
|
||||
grantPermissions(7, "scott", BasePermission.ADMINISTRATION);
|
||||
grantPermissions(8, "dianne", BasePermission.ADMINISTRATION);
|
||||
grantPermissions(8, "dianne", BasePermission.READ);
|
||||
grantPermissions(8, "scott", BasePermission.READ);
|
||||
grantPermissions(9, "scott", BasePermission.ADMINISTRATION);
|
||||
grantPermissions(9, "scott", BasePermission.READ);
|
||||
grantPermissions(9, "scott", BasePermission.WRITE);
|
||||
grantPermissions(9, "scott", BasePermission.DELETE);
|
||||
|
||||
// Now expressly change the owner of the first ten contacts
|
||||
// We have to do this last, because "rod" owns all of them (doing it sooner would
|
||||
// prevent ACL updates)
|
||||
// Note that ownership has no impact on permissions - they're separate (ownership
|
||||
// only allows ACl editing)
|
||||
changeOwner(5, "dianne");
|
||||
changeOwner(6, "dianne");
|
||||
changeOwner(7, "scott");
|
||||
changeOwner(8, "dianne");
|
||||
changeOwner(9, "scott");
|
||||
|
||||
String[] users = { "bill", "bob", "jane" }; // don't want to mess around with
|
||||
// consistent sample data
|
||||
Permission[] permissions = { BasePermission.ADMINISTRATION, BasePermission.READ,
|
||||
BasePermission.DELETE };
|
||||
|
||||
for (int i = 10; i < createEntities; i++) {
|
||||
String user = users[rnd.nextInt(users.length)];
|
||||
Permission permission = permissions[rnd.nextInt(permissions.length)];
|
||||
grantPermissions(i, user, permission);
|
||||
|
||||
String user2 = users[rnd.nextInt(users.length)];
|
||||
Permission permission2 = permissions[rnd.nextInt(permissions.length)];
|
||||
grantPermissions(i, user2, permission2);
|
||||
}
|
||||
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
private void changeOwner(int contactNumber, String newOwnerUsername) {
|
||||
AclImpl acl = (AclImpl) mutableAclService.readAclById(new ObjectIdentityImpl(
|
||||
Contact.class, new Long(contactNumber)));
|
||||
acl.setOwner(new PrincipalSid(newOwnerUsername));
|
||||
updateAclInTransaction(acl);
|
||||
}
|
||||
|
||||
public int getCreateEntities() {
|
||||
return createEntities;
|
||||
}
|
||||
|
||||
private void grantPermissions(int contactNumber, String recipientUsername,
|
||||
Permission permission) {
|
||||
AclImpl acl = (AclImpl) mutableAclService.readAclById(new ObjectIdentityImpl(
|
||||
Contact.class, new Long(contactNumber)));
|
||||
acl.insertAce(acl.getEntries().size(), permission, new PrincipalSid(
|
||||
recipientUsername), true);
|
||||
updateAclInTransaction(acl);
|
||||
}
|
||||
|
||||
private String[] selectPerson() {
|
||||
String firstName = firstNames[rnd.nextInt(firstNames.length)];
|
||||
String lastName = lastNames[rnd.nextInt(lastNames.length)];
|
||||
|
||||
return new String[] { firstName, lastName, firstName + " " + lastName };
|
||||
}
|
||||
|
||||
public void setCreateEntities(int createEntities) {
|
||||
this.createEntities = createEntities;
|
||||
}
|
||||
|
||||
public void setDataSource(DataSource dataSource) {
|
||||
this.template = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
public void setMutableAclService(MutableAclService mutableAclService) {
|
||||
this.mutableAclService = mutableAclService;
|
||||
}
|
||||
|
||||
public void setPlatformTransactionManager(
|
||||
PlatformTransactionManager platformTransactionManager) {
|
||||
this.tt = new TransactionTemplate(platformTransactionManager);
|
||||
}
|
||||
|
||||
private void updateAclInTransaction(final MutableAcl acl) {
|
||||
tt.execute(new TransactionCallback<Object>() {
|
||||
public Object doInTransaction(TransactionStatus arg0) {
|
||||
mutableAclService.updateAcl(acl);
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* 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.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.PermissionEvaluator;
|
||||
import org.springframework.security.acls.AclPermissionEvaluator;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
* Controller which handles simple, single request use cases such as index pages and
|
||||
* contact deletion.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
*/
|
||||
@Controller
|
||||
public class IndexController {
|
||||
private final static Permission[] HAS_DELETE = new Permission[] {
|
||||
BasePermission.DELETE, BasePermission.ADMINISTRATION };
|
||||
private final static Permission[] HAS_ADMIN = new Permission[] { BasePermission.ADMINISTRATION };
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
@Autowired
|
||||
private ContactManager contactManager;
|
||||
@Autowired
|
||||
private PermissionEvaluator permissionEvaluator;
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
/**
|
||||
* The public index page, used for unauthenticated users.
|
||||
*/
|
||||
@RequestMapping(value = "/hello.htm", method = RequestMethod.GET)
|
||||
public ModelAndView displayPublicIndex() {
|
||||
Contact rnd = contactManager.getRandomContact();
|
||||
|
||||
return new ModelAndView("hello", "contact", rnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* The index page for an authenticated user.
|
||||
* <p>
|
||||
* This controller displays a list of all the contacts for which the current user has
|
||||
* read or admin permissions. It makes a call to {@link ContactManager#getAll()} which
|
||||
* automatically filters the returned list using Spring Security's ACL mechanism (see
|
||||
* the expression annotations on this interface for the details).
|
||||
* <p>
|
||||
* In addition to rendering the list of contacts, the view will also include a "Del"
|
||||
* or "Admin" link beside the contact, depending on whether the user has the
|
||||
* corresponding permissions (admin permission is assumed to imply delete here). This
|
||||
* information is stored in the model using the injected {@link PermissionEvaluator}
|
||||
* instance. The implementation should be an instance of
|
||||
* {@link AclPermissionEvaluator} or one which is compatible with Spring Security's
|
||||
* ACL module.
|
||||
*/
|
||||
@RequestMapping(value = "/secure/index.htm", method = RequestMethod.GET)
|
||||
public ModelAndView displayUserContacts() {
|
||||
List<Contact> myContactsList = contactManager.getAll();
|
||||
Map<Contact, Boolean> hasDelete = new HashMap<Contact, Boolean>(
|
||||
myContactsList.size());
|
||||
Map<Contact, Boolean> hasAdmin = new HashMap<Contact, Boolean>(
|
||||
myContactsList.size());
|
||||
|
||||
Authentication user = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
for (Contact contact : myContactsList) {
|
||||
hasDelete.put(contact, Boolean.valueOf(permissionEvaluator.hasPermission(
|
||||
user, contact, HAS_DELETE)));
|
||||
hasAdmin.put(contact, Boolean.valueOf(permissionEvaluator.hasPermission(user,
|
||||
contact, HAS_ADMIN)));
|
||||
}
|
||||
|
||||
Map<String, Object> model = new HashMap<String, Object>();
|
||||
model.put("contacts", myContactsList);
|
||||
model.put("hasDeletePermission", hasDelete);
|
||||
model.put("hasAdminPermission", hasAdmin);
|
||||
|
||||
return new ModelAndView("index", "model", model);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 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;
|
||||
|
||||
/**
|
||||
* An object that represents user-editable sections of a {@link Contact}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class WebContact {
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private String email;
|
||||
private String name;
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 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.validation.Errors;
|
||||
import org.springframework.validation.Validator;
|
||||
|
||||
/**
|
||||
* Validates {@link WebContact}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class WebContactValidator implements Validator {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean supports(Class clazz) {
|
||||
return clazz.equals(WebContact.class);
|
||||
}
|
||||
|
||||
public void validate(Object obj, Errors errors) {
|
||||
WebContact wc = (WebContact) obj;
|
||||
|
||||
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)
|
||||
|| (wc.getEmail().length() > 50)) {
|
||||
errors.rejectValue("email", "err.email",
|
||||
"Email 3-50 characters is required. *");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user