From 8cd7a03fac342f115c6a1897ee80778c97e6393c Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Wed, 5 Sep 2007 11:40:31 +0000 Subject: [PATCH] SEC-540: removed doc project module. --- doc/.cvsignore | 2 - doc/docbook/acegi.xml | 6337 ------------------- doc/docbook/images/ACLSecurity.gif | Bin 4041 -> 0 bytes doc/docbook/images/AccessDecisionVoting.gif | Bin 6481 -> 0 bytes doc/docbook/images/AfterInvocation.gif | Bin 4672 -> 0 bytes doc/docbook/images/Authentication.gif | Bin 12955 -> 0 bytes doc/docbook/images/BasicAclProvider.gif | Bin 9921 -> 0 bytes doc/docbook/images/Context.gif | Bin 4269 -> 0 bytes doc/docbook/images/Permissions.gif | Bin 14168 -> 0 bytes doc/docbook/images/SecurityInterception.gif | Bin 5532 -> 0 bytes doc/docbook/images/admons/blank.png | Bin 374 -> 0 bytes doc/docbook/images/admons/caution.gif | Bin 743 -> 0 bytes doc/docbook/images/admons/caution.png | Bin 1250 -> 0 bytes doc/docbook/images/admons/caution.tif | Bin 1978 -> 0 bytes doc/docbook/images/admons/draft.png | Bin 17454 -> 0 bytes doc/docbook/images/admons/home.gif | Bin 321 -> 0 bytes doc/docbook/images/admons/home.png | Bin 1156 -> 0 bytes doc/docbook/images/admons/important.gif | Bin 1003 -> 0 bytes doc/docbook/images/admons/important.png | Bin 722 -> 0 bytes doc/docbook/images/admons/important.tif | Bin 2020 -> 0 bytes doc/docbook/images/admons/next.gif | Bin 1083 -> 0 bytes doc/docbook/images/admons/next.png | Bin 1150 -> 0 bytes doc/docbook/images/admons/note.gif | Bin 580 -> 0 bytes doc/docbook/images/admons/note.png | Bin 490 -> 0 bytes doc/docbook/images/admons/note.tif | Bin 460 -> 0 bytes doc/docbook/images/admons/prev.gif | Bin 1118 -> 0 bytes doc/docbook/images/admons/prev.png | Bin 1132 -> 0 bytes doc/docbook/images/admons/tip.gif | Bin 598 -> 0 bytes doc/docbook/images/admons/tip.png | Bin 449 -> 0 bytes doc/docbook/images/admons/tip.tif | Bin 420 -> 0 bytes doc/docbook/images/admons/toc-blank.png | Bin 318 -> 0 bytes doc/docbook/images/admons/toc-minus.png | Bin 259 -> 0 bytes doc/docbook/images/admons/toc-plus.png | Bin 264 -> 0 bytes doc/docbook/images/admons/up.gif | Bin 1089 -> 0 bytes doc/docbook/images/admons/up.png | Bin 1111 -> 0 bytes doc/docbook/images/admons/warning.gif | Bin 743 -> 0 bytes doc/docbook/images/admons/warning.png | Bin 1241 -> 0 bytes doc/docbook/images/admons/warning.tif | Bin 1990 -> 0 bytes doc/docbook/images/callouts/1.gif | Bin 968 -> 0 bytes doc/docbook/images/callouts/1.png | Bin 329 -> 0 bytes doc/docbook/images/callouts/10.gif | Bin 968 -> 0 bytes doc/docbook/images/callouts/10.png | Bin 361 -> 0 bytes doc/docbook/images/callouts/11.gif | Bin 244 -> 0 bytes doc/docbook/images/callouts/11.png | Bin 565 -> 0 bytes doc/docbook/images/callouts/12.gif | Bin 244 -> 0 bytes doc/docbook/images/callouts/12.png | Bin 617 -> 0 bytes doc/docbook/images/callouts/13.gif | Bin 244 -> 0 bytes doc/docbook/images/callouts/13.png | Bin 623 -> 0 bytes doc/docbook/images/callouts/14.gif | Bin 244 -> 0 bytes doc/docbook/images/callouts/14.png | Bin 411 -> 0 bytes doc/docbook/images/callouts/15.gif | Bin 244 -> 0 bytes doc/docbook/images/callouts/15.png | Bin 640 -> 0 bytes doc/docbook/images/callouts/2.gif | Bin 968 -> 0 bytes doc/docbook/images/callouts/2.png | Bin 353 -> 0 bytes doc/docbook/images/callouts/3.gif | Bin 968 -> 0 bytes doc/docbook/images/callouts/3.png | Bin 350 -> 0 bytes doc/docbook/images/callouts/4.gif | Bin 968 -> 0 bytes doc/docbook/images/callouts/4.png | Bin 345 -> 0 bytes doc/docbook/images/callouts/5.gif | Bin 968 -> 0 bytes doc/docbook/images/callouts/5.png | Bin 348 -> 0 bytes doc/docbook/images/callouts/6.gif | Bin 968 -> 0 bytes doc/docbook/images/callouts/6.png | Bin 355 -> 0 bytes doc/docbook/images/callouts/7.gif | Bin 968 -> 0 bytes doc/docbook/images/callouts/7.png | Bin 344 -> 0 bytes doc/docbook/images/callouts/8.gif | Bin 968 -> 0 bytes doc/docbook/images/callouts/8.png | Bin 357 -> 0 bytes doc/docbook/images/callouts/9.gif | Bin 968 -> 0 bytes doc/docbook/images/callouts/9.png | Bin 357 -> 0 bytes doc/docbook/images/logo.gif | Bin 8919 -> 0 bytes doc/docbook/images/logo.psd | Bin 149793 -> 0 bytes doc/docbook/styles/fo/acegi.xsl | 439 -- doc/docbook/styles/xhtml/acegi-chunk.xsl | 96 - doc/docbook/styles/xhtml/acegi.css | 168 - doc/docbook/styles/xhtml/acegi.xsl | 94 - doc/pom.xml | 54 - doc/xdocs/articles.xml | 153 - doc/xdocs/building.xml | 40 - doc/xdocs/changes.xml | 293 - doc/xdocs/cvs-usage.xml | 33 - doc/xdocs/dbinit.txt | 92 - doc/xdocs/downloads.xml | 28 - doc/xdocs/faq.xml | 207 - doc/xdocs/index.xml | 176 - doc/xdocs/navigation.xml | 81 - doc/xdocs/petclinic-tutorial.xml | 168 - doc/xdocs/policies.xml | 103 - doc/xdocs/powering.xml | 39 - doc/xdocs/reference.xml | 69 - doc/xdocs/standalone.xml | 50 - doc/xdocs/suggested.xml | 105 - doc/xdocs/upgrade/upgrade-03-04.xml | 48 - doc/xdocs/upgrade/upgrade-04-05.xml | 54 - doc/xdocs/upgrade/upgrade-05-06.xml | 76 - doc/xdocs/upgrade/upgrade-06-070.xml | 55 - doc/xdocs/upgrade/upgrade-070-080.xml | 41 - doc/xdocs/upgrade/upgrade-080-090.xml | 95 - doc/xdocs/upgrade/upgrade-090-100.xml | 92 - pom.xml | 3 - 98 files changed, 9291 deletions(-) delete mode 100644 doc/.cvsignore delete mode 100644 doc/docbook/acegi.xml delete mode 100644 doc/docbook/images/ACLSecurity.gif delete mode 100644 doc/docbook/images/AccessDecisionVoting.gif delete mode 100644 doc/docbook/images/AfterInvocation.gif delete mode 100644 doc/docbook/images/Authentication.gif delete mode 100644 doc/docbook/images/BasicAclProvider.gif delete mode 100644 doc/docbook/images/Context.gif delete mode 100644 doc/docbook/images/Permissions.gif delete mode 100644 doc/docbook/images/SecurityInterception.gif delete mode 100644 doc/docbook/images/admons/blank.png delete mode 100644 doc/docbook/images/admons/caution.gif delete mode 100644 doc/docbook/images/admons/caution.png delete mode 100644 doc/docbook/images/admons/caution.tif delete mode 100644 doc/docbook/images/admons/draft.png delete mode 100644 doc/docbook/images/admons/home.gif delete mode 100644 doc/docbook/images/admons/home.png delete mode 100644 doc/docbook/images/admons/important.gif delete mode 100644 doc/docbook/images/admons/important.png delete mode 100644 doc/docbook/images/admons/important.tif delete mode 100644 doc/docbook/images/admons/next.gif delete mode 100644 doc/docbook/images/admons/next.png delete mode 100644 doc/docbook/images/admons/note.gif delete mode 100644 doc/docbook/images/admons/note.png delete mode 100644 doc/docbook/images/admons/note.tif delete mode 100644 doc/docbook/images/admons/prev.gif delete mode 100644 doc/docbook/images/admons/prev.png delete mode 100644 doc/docbook/images/admons/tip.gif delete mode 100644 doc/docbook/images/admons/tip.png delete mode 100644 doc/docbook/images/admons/tip.tif delete mode 100644 doc/docbook/images/admons/toc-blank.png delete mode 100644 doc/docbook/images/admons/toc-minus.png delete mode 100644 doc/docbook/images/admons/toc-plus.png delete mode 100644 doc/docbook/images/admons/up.gif delete mode 100644 doc/docbook/images/admons/up.png delete mode 100644 doc/docbook/images/admons/warning.gif delete mode 100644 doc/docbook/images/admons/warning.png delete mode 100644 doc/docbook/images/admons/warning.tif delete mode 100644 doc/docbook/images/callouts/1.gif delete mode 100644 doc/docbook/images/callouts/1.png delete mode 100644 doc/docbook/images/callouts/10.gif delete mode 100644 doc/docbook/images/callouts/10.png delete mode 100644 doc/docbook/images/callouts/11.gif delete mode 100644 doc/docbook/images/callouts/11.png delete mode 100644 doc/docbook/images/callouts/12.gif delete mode 100644 doc/docbook/images/callouts/12.png delete mode 100644 doc/docbook/images/callouts/13.gif delete mode 100644 doc/docbook/images/callouts/13.png delete mode 100644 doc/docbook/images/callouts/14.gif delete mode 100644 doc/docbook/images/callouts/14.png delete mode 100644 doc/docbook/images/callouts/15.gif delete mode 100644 doc/docbook/images/callouts/15.png delete mode 100644 doc/docbook/images/callouts/2.gif delete mode 100644 doc/docbook/images/callouts/2.png delete mode 100644 doc/docbook/images/callouts/3.gif delete mode 100644 doc/docbook/images/callouts/3.png delete mode 100644 doc/docbook/images/callouts/4.gif delete mode 100644 doc/docbook/images/callouts/4.png delete mode 100644 doc/docbook/images/callouts/5.gif delete mode 100644 doc/docbook/images/callouts/5.png delete mode 100644 doc/docbook/images/callouts/6.gif delete mode 100644 doc/docbook/images/callouts/6.png delete mode 100644 doc/docbook/images/callouts/7.gif delete mode 100644 doc/docbook/images/callouts/7.png delete mode 100644 doc/docbook/images/callouts/8.gif delete mode 100644 doc/docbook/images/callouts/8.png delete mode 100644 doc/docbook/images/callouts/9.gif delete mode 100644 doc/docbook/images/callouts/9.png delete mode 100644 doc/docbook/images/logo.gif delete mode 100644 doc/docbook/images/logo.psd delete mode 100644 doc/docbook/styles/fo/acegi.xsl delete mode 100644 doc/docbook/styles/xhtml/acegi-chunk.xsl delete mode 100644 doc/docbook/styles/xhtml/acegi.css delete mode 100644 doc/docbook/styles/xhtml/acegi.xsl delete mode 100644 doc/pom.xml delete mode 100644 doc/xdocs/articles.xml delete mode 100644 doc/xdocs/building.xml delete mode 100644 doc/xdocs/changes.xml delete mode 100644 doc/xdocs/cvs-usage.xml delete mode 100644 doc/xdocs/dbinit.txt delete mode 100644 doc/xdocs/downloads.xml delete mode 100644 doc/xdocs/faq.xml delete mode 100644 doc/xdocs/index.xml delete mode 100644 doc/xdocs/navigation.xml delete mode 100644 doc/xdocs/petclinic-tutorial.xml delete mode 100644 doc/xdocs/policies.xml delete mode 100644 doc/xdocs/powering.xml delete mode 100644 doc/xdocs/reference.xml delete mode 100644 doc/xdocs/standalone.xml delete mode 100644 doc/xdocs/suggested.xml delete mode 100644 doc/xdocs/upgrade/upgrade-03-04.xml delete mode 100644 doc/xdocs/upgrade/upgrade-04-05.xml delete mode 100644 doc/xdocs/upgrade/upgrade-05-06.xml delete mode 100644 doc/xdocs/upgrade/upgrade-06-070.xml delete mode 100644 doc/xdocs/upgrade/upgrade-070-080.xml delete mode 100644 doc/xdocs/upgrade/upgrade-080-090.xml delete mode 100644 doc/xdocs/upgrade/upgrade-090-100.xml diff --git a/doc/.cvsignore b/doc/.cvsignore deleted file mode 100644 index 7407898382..0000000000 --- a/doc/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -target -build.properties diff --git a/doc/docbook/acegi.xml b/doc/docbook/acegi.xml deleted file mode 100644 index cc076c4d4a..0000000000 --- a/doc/docbook/acegi.xml +++ /dev/null @@ -1,6337 +0,0 @@ - - - - - - - Acegi Security - - Reference Documentation - - 1.0.5 - - - - Ben - - Alex - - - - - - - - Preface - - Acegi Security provides a comprehensive security solution for - J2EE-based enterprise software applications. As you will discover as you - venture through this reference guide, we have tried to provide you a - useful and highly configurable security system. - - Security is an ever-moving target, and it's important to pursue a - comprehensive, system-wide approach. In security circles we encourage you - to adopt "layers of security", so that each layer tries to be as secure as - possible in its own right, with successive layers providing additional - security. The "tighter" the security of each layer, the more robust and - safe your application will be. At the bottom level you'll need to deal - with issues such as transport security and system identification, in order - to mitigate man-in-the-middle attacks. Next you'll generally utilise - firewalls, perhaps with VPNs or IP security to ensure only authorised - systems can attempt to connect. In corporate environments you may deploy a - DMZ to separate public-facing servers from backend database and - application servers. Your operating system will also play a critical part, - addressing issues such as running processes as non-privileged users and - maximising file system security. An operating system will usually also be - configured with its own firewall. Hopefully somewhere along the way you'll - be trying to prevent denial of service and brute force attacks against the - system. An intrusion detection system will also be especially useful for - monitoring and responding to attacks, with such systems able to take - protective action such as blocking offending TCP/IP addresses in - real-time. Moving to the higher layers, your Java Virtual Machine will - hopefully be configured to minimize the permissions granted to different - Java types, and then your application will add its own problem - domain-specific security configuration. Acegi Security makes this latter - area - application security - much easier. - - Of course, you will need to properly address all security layers - mentioned above, together with managerial factors that encompass every - layer. A non-exhaustive list of such managerial factors would include - security bulletin monitoring, patching, personnel vetting, audits, change - control, engineering management systems, data backup, disaster recovery, - performance benchmarking, load monitoring, centralised logging, incident - response procedures etc. - - With Acegi Security being focused on helping you with the enterprise - application security layer, you will find that there are as many different - requirements as there are business problem domains. A banking application - has different needs from an ecommerce application. An ecommerce - application has different needs from a corporate sales force automation - tool. These custom requirements make application security interesting, - challenging and rewarding. - - This reference guide has been largely restructured for the 1.0.0 - release of Acegi Security. Please read Part I, Overall Architecture, in its - entirety. The remaining parts of the reference guide are structured in a - more traditional reference style, designed to be read on an as-required - basis. - - We hope that you find this reference guide useful, and we welcome - your feedback and suggestions. - - Finally, welcome to the Acegi Security community. - - - - Overall Architecture - - - Like most software, Acegi Security has certain central interfaces, - classes and conceptual abstractions that are commonly used throughout - the framework. In this part of the reference guide we will introduce - Acegi Security, before examining these central elements that are - necessary to successfully planning and executing an Acegi Security - integration. - - - - Introduction - - - What is Acegi Security? - - Acegi Security provides comprehensive security services for - J2EE-based enterprise software applications. There is a particular - emphasis on supporting projects built using The Spring Framework, - which is the leading J2EE solution for enterprise software - development. If you're not using Spring for developing enterprise - applications, we warmly encourage you to take a closer look at it. - Some familiarity with Spring - and in particular dependency injection - principles - will help you get up to speed with Acegi Security more - easily. - - People use Acegi Security for many reasons, but most are drawn - to the project after finding the security features of J2EE's Servlet - Specification or EJB Specification lack the depth required for typical - enterprise application scenarios. Whilst mentioning these standards, - it's important to recognise that they are not portable at a WAR or EAR - level. Therefore, if you switch server environments, it is typically a - lot of work to reconfigure your application's security in the new - target environment. Using Acegi Security overcomes these problems, and - also brings you dozens of other useful, entirely customisable security - features. - - As you probably know, security comprises two major operations. - The first is known as "authentication", which is the process of - establishing a principal is who they claim to be. A "principal" - generally means a user, device or some other system which can perform - an action in your application. "Authorization" refers to the process - of deciding whether a principal is allowed to perform an action in - your application. To arrive at the point where an authorization - decision is needed, the identity of the principal has already been - established by the authentication process. These concepts are common, - and not at all specific to Acegi Security. - - At an authentication level, Acegi Security supports a wide range - of authentication models. Most of these authentication models are - either provided by third parties, or are developed by relevant - standards bodies such as the Internet Engineering Task Force. In - addition, Acegi Security provides its own set of authentication - features. Specifically, Acegi Security currently supports - authentication with all of these technologies: - - - - HTTP BASIC authentication headers (an IEFT RFC-based - standard) - - - - HTTP Digest authentication headers (an IEFT RFC-based - standard) - - - - HTTP X.509 client certificate exchange (an IEFT RFC-based - standard) - - - - LDAP (a very common approach to cross-platform - authentication needs, especially in large environments) - - - - Form-based authentication (for simple user interface - needs) - - - - Computer Associates Siteminder - - - - JA-SIG Central Authentication Service (otherwise known as - CAS, which is a popular open source single sign on system) - - - - Transparent authentication context propagation for Remote - Method Invocation (RMI) and HttpInvoker (a Spring remoting - protocol) - - - - Automatic "remember-me" authentication (so you can tick a - box to avoid re-authentication for a predetermined period of - time) - - - - Anonymous authentication (allowing every call to - automatically assume a particular security identity) - - - - Run-as authentication (which is useful if one call should - proceed with a different security identity) - - - - Java Authentication and Authorization Service (JAAS) - - - - Container integration with JBoss, Jetty, Resin and Tomcat - (so you can still use Container Manager Authentication if - desired) - - - - Your own authentication systems (see below) - - - - Many independent software vendors (ISVs) adopt Acegi Security - because of this rich choice of authentication models. Doing so allows - them to quickly integrate their solutions with whatever their end - clients need, without undertaking a lot of engineering or requiring - the client to change their environment. If none of the above - authentication mechanisms suit your needs, Acegi Security is an open - platform and it is quite simple to write your own authentication - mechanism. Many corporate users of Acegi Security need to integrate - with "legacy" systems that don't follow any particular security - standards, and Acegi Security is happy to "play nicely" with such - systems. - - Sometimes the mere process of authentication isn't enough. - Sometimes you need to also differentiate security based on the way a - principal is interacting with your application. For example, you might - want to ensure requests only arrive over HTTPS, in order to protect - passwords from eavesdropping or end users from man-in-the-middle - attacks. Or, you might want to ensure that an actual human being is - making the requests and not some robot or other automated process. - This is especially helpful to protect password recovery processes from - brute force attacks, or simply to make it harder for people to - duplicate your application's key content. To help you achieve these - goals, Acegi Security fully supports automatic "channel security", - together with JCaptcha integration for human user detection. - - Irrespective of how authentication was undertaken, Acegi - Security provides a deep set of authorization capabilities. There are - three main areas of interest in respect of authorization, these being - authorizing web requests, authorizing methods can be invoked, and - authorizing access to individual domain object instances. To help you - understand the differences, consider the authorization capabilities - found in the Servlet Specification web pattern security, EJB Container - Managed Security and file system security respectively. Acegi Security - provides deep capabilities in all of these important areas, which - we'll explore later in this reference guide. - - - - History - - Acegi Security began in late 2003, when a question was posed on - the Spring Developers' mailing list asking whether there had been any - consideration given to a Spring-based security implementation. At the - time the Spring community was relatively small (especially by today's - size!), and indeed Spring itself had only existed as a SourceForge - project from early 2003. The response to the question was that it was - a worthwhile area, although a lack of time currently prevented its - exploration. - - With that in mind, a simple security implementation was built - and not released. A few weeks later another member of the Spring - community inquired about security, and at the time this code was - offered to them. Several other requests followed, and by January 2004 - around twenty people were using the code. These pioneering users were - joined by others who suggested a SourceForge project was in order, - which was duly established in March 2004. - - In those early days, the project didn't have any of its own - authentication modules. Container Managed Security was relied upon for - the authentication process, with Acegi Security instead focusing on - authorization. This was suitable at first, but as more and more users - requested additional container support, the fundamental limitation of - container-specific authentication realm interfaces was experienced. - There was also a related issue of adding new JARs to the container's - classpath, which was a common source of end user confusion and - misconfiguration. - - Acegi Security-specific authentication services were - subsequently introduced. Around a year later, the Acegi Security - became an official Spring Framework subproject. The 1.0.0 final - release was published in May 2006 - after more than two and a half - years of active use in numerous production software projects and many - hundreds of improvements and community contributions. - - Today Acegi Security enjoys a strong and active open source - community. There are thousands of messages about Acegi Security on the - support forums. Fourteen developers work on the code itself, with an - active community who also regularly share patches and support their - peers. - - - - Release Numbering - - It is useful to understand how Acegi Security release numbers - work, as it will help you identify the effort (or lack thereof) - involved in migrating to future releases of the project. Officially, - we use the Apache Portable Runtime Project versioning guidelines, - which can be viewed at - http://apr.apache.org/versioning.html. We quote the - introduction contained on that page for your convenience: - - Versions are denoted using a standard triplet of - integers: MAJOR.MINOR.PATCH. The basic intent is that MAJOR versions - are incompatible, large-scale upgrades of the API. MINOR versions - retain source and binary compatibility with older minor versions, and - changes in the PATCH level are perfectly compatible, forwards and - backwards. - - - - - Technical Overview - - - Runtime Environment - - Acegi Security is written to execute within a standard Java 1.3 - Runtime Environment. It also supports Java 5.0, although the Java - types which are specific to this release are packaged in a separate - package with the suffix "tiger" in their JAR filename. As Acegi - Security aims to operate in a self-contained manner, there is no need - to place any special configuration files into your Java Runtime - Environment. In particular, there is no need to configure a special - Java Authentication and Authorization Service (JAAS) policy file or - place Acegi Security into common classpath locations. - - Similarly, if you are using an EJB Container or Servlet - Container there is no need to put any special configuration files - anywhere, nor include Acegi Security in a server classloader. - - This above design offers maximum deployment time flexibility, as - you can simply copy your target artifact (be it a JAR, WAR or EAR) - from one system to another and it will immediately work. - - - - Shared Components - - Let's explore some of the most important shared components in - Acegi Security. Components are considered "shared" if they are central - to the framework and the framework cannot operate without them. These - Java types represent the building blocks of the remaining system, so - it's important to understand that they're there, even if you don't - need to directly interact with them. - - The most fundamental object is - SecurityContextHolder. This is where we store - details of the present security context of the application, which - includes details of the principal currently using the application. By - default the SecurityContextHolder uses a - ThreadLocal to store these details, which means - that the security context is always available to methods in the same - thread of execution, even if the security context is not explicitly - passed around as an argument to those methods. Using a - ThreadLocal in this way is quite safe if care is - taken to clear the thread after the present principal's request is - processed. Of course, Acegi Security takes care of this for you - automatically so there is no need to worry about it. - - Some applications aren't entirely suitable for using a - ThreadLocal, because of the specific way they work - with threads. For example, a Swing client might want all threads in a - Java Virtual Machine to use the same security context. For this - situation you would use the - SecurityContextHolder.MODE_GLOBAL. Other - applications might want to have threads spawned by the secure thread - also assume the same security identity. This is achieved by using - SecurityContextHolder.MODE_INHERITABLETHREADLOCAL. - You can change the mode from the default - SecurityContextHolder.MODE_THREADLOCAL in two ways. - The first is to set a system property. Alternatively, call a static - method on SecurityContextHolder. Most applications - won't need to change from the default, but if you do, take a look at - the JavaDocs for SecurityContextHolder to learn - more. - - Inside the SecurityContextHolder we store - details of the principal currently interacting with the application. - Acegi Security uses an Authentication object to - represent this information. Whilst you won't normally need to create - an Authentication object yourself, it is fairly - common for users to query the Authentication - object. You can use the following code block - from anywhere in your - application - to do this: - - Object obj = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - -if (obj instanceof UserDetails) { - String username = ((UserDetails)obj).getUsername(); -} else { - String username = obj.toString(); -} - - The above code introduces a number of interesting relationships - and key objects. First, you will notice that there is an intermediate - object between SecurityContextHolder and - Authentication. The - SecurityContextHolder.getContext() method is - actually returning a SecurityContext. Acegi - Security uses a few different SecurityContext - implementations, such as if we need to store special information - related to a request that is not principal-specific. A good example of - this is our JCaptcha integration, which needs to know whether the - current request came from a human user or not. Because such a decision - has nothing at all to do with the principal the request may or may not - be authenticated as, we store it in the - SecurityContext. - - Another item to note from the above code fragment is that you - can obtain a principal from the Authentication - object. The principal is just an Object. Most of - the time this can be cast into a UserDetails - object. UserDetails is a central interface in Acegi - Security. It represents a principal, but in an extensible and - application-specific way. Think of UserDetails as - the adapter between your own user database and what Acegi Security - needs inside the SecurityContextHolder. Being a - representation of something from your own user database, quite often - you will cast the UserDetails to the original - object that your application provided, so you can call - business-specific methods (like getEmail(), - getEmployeeNumber() and so on). - - By now you're probably wondering, so when do I provide a - UserDetails object? How do I do that? I thought you - said this thing was declarative and I didn't need to write any Java - code - what gives? The short answer is that there is a special - interface called UserDetailsService. The only - method on this interface accepts a String-based - username argument and returns a UserDetails. Most - authentication providers that ship with Acegi Security delegate to a - UserDetailsService as part of the authentication - process. The UserDetailsService is used to build - the Authentication object that is stored in the - SecurityContextHolder. The good news is that we - provide a number of UserDetailsService - implementations, including one that uses an in-memory map and another - that uses JDBC. Most users tend to write their own, though, with such - implementations often simply sitting on top of an existing Data Access - Object (DAO) that represents their employees, customers, or other - users of the enterprise application. Remember the advantage that - whatever your UserDetailsService returns can always be obtained from - the SecurityContextHolder, as per the above code - fragment. - - Besides the principal, another important method provided by - Authentication is - getAuthorities(). This method provides an array of - GrantedAuthority objects. A - GrantedAuthority is, not surprisingly, an authority - that is granted to the principal. Such authorities are usually - "roles", such as ROLE_ADMINISTRATOR or - ROLE_HR_SUPERVISOR. These roles are later on - configured for web authorization, method authorization and domain - object authorization. Other parts of Acegi Security are capable of - interpreting these authorities, and expect them to be present. - GrantedAuthority objects are usually loaded by - the UserDetailsService. - - Usually the GrantedAuthority objects are - application-wide permissions. They are not specific to a given domain - object. Thus, you wouldn't likely have a - GrantedAuthority to represent a permission to - Employee object number 54, because if there are - thousands of such authorities you would quickly run out of memory (or, - at the very least, cause the application to take a long time to - authenticate a user). Of course, Acegi Security is expressly designed - to handle this common requirement, but you'd instead use the project's - domain object security capabilities for this purpose. - - Last but not least, sometimes you will need to store the - SecurityContext between HTTP requests. Other times - the principal will re-authenticate on every request, although most of - the time it will be stored. The - HttpSessionContextIntegrationFilter is responsible - for storing a SecurityContext between HTTP - requests. As suggested by the name of the class, the - HttpSession is used to store this information. You - should never interact directly with the HttpSession - for security purposes. There is simply no justification for doing so - - always use the SecurityContextHolder - instead. - - Just to recap, the major building blocks of Acegi Security - are: - - - - SecurityContextHolder, to provide any - type access to the SecurityContext. - - - - SecurityContext, to hold the - Authentication and possibly request-specific - security information. - - - - HttpSessionContextIntegrationFilter, to - store the SecurityContext in the - HttpSession between web requests. - - - - Authentication, to represent the - principal in an Acegi Security-specific manner. - - - - GrantedAuthority, to reflect the - application-wide permissions granted to a principal. - - - - UserDetails, to provide the necessary - information to build an Authentication object from your - application's DAOs. - - - - UserDetailsService, to create a - UserDetails when passed in a - String-based username (or certificate ID or - alike). - - - - Now that you've gained an understanding of these repeatedly-used - components, let's take a closer look at the process of - authentication. - - - - Authentication - - As mentioned in the beginning of this reference guide, Acegi - Security can participate in many different authentication - environments. Whilst we recommend people use Acegi Security for - authentication and not integrate with existing Container Managed - Authentication, it is nevertheless supported - as is integrating with - your own proprietary authentication system. Let's first explore - authentication from the perspective of Acegi Security managing web - security entirely on its own, which is illustrative of the most - complex and most common situation. - - Consider a typical web application's authentication - process: - - - - You visit the home page, and click on a link. - - - - A request goes to the server, and the server decides that - you've asked for a protected resource. - - - - As you're not presently authenticated, the server sends back - a response indicating that you must authenticate. The response - will either be an HTTP response code, or a redirect to a particular - web page. - - - - Depending on the authentication mechanism, your browser will - either redirect to the specific web page so that you can fill out - the form, or the browser will somehow retrieve your identity (eg a - BASIC authentication dialogue box, a cookie, a X509 certificate - etc). - - - - The browser will send back a response to the server. This - will either be an HTTP POST containing the contents of the form - that you filled out, or an HTTP header containing your - authentication details. - - - - Next the server will decide whether or not the presented - credentials are valid. If they're valid, the next step will - happen. If they're invalid, usually your browser will be asked to - try again (so you return to step two above). - - - - The original request that you made to cause the - authentication process will be retried. Hopefully you've - authenticated with sufficient granted authorities to access the - protected resource. If you have sufficient access, the request - will be successful. Otherwise, you'll receive back an HTTP error - code 403, which means "forbidden". - - - - Acegi Security has distinct classes responsible for most of the - steps described above. The main participants (in the order that they - are used) are the ExceptionTranslationFilter, an - AuthenticationEntryPoint, an authentication - mechanism, and an AuthenticationProvider. - - ExceptionTranslationFilter is an Acegi - Security filter that has responsibility for detecting any Acegi - Security exceptions that are thrown. Such exceptions will generally be - thrown by an AbstractSecurityInterceptor, which is - the main provider of authorization services. We will discuss - AbstractSecurityInterceptor in the next section, - but for now we just need to know that it produces Java exceptions and - knows nothing about HTTP or how to go about authenticating a - principal. Instead the ExceptionTranslationFilter - offers this service, with specific responsibility for either returning - error code 403 (if the principal has been authenticated and therefore - simply lacks sufficient access - as per step seven above), or - launching an AuthenticationEntryPoint (if the - principal has not been authenticated and therefore we need to go - commence step three). - - The AuthenticationEntryPoint is responsible - for step three in the above list. As you can imagine, each web - application will have a default authentication strategy (well, this - can be configured like nearly everything else in Acegi Security, but - let's keep it simple for now). Each major authentication system will - have its own AuthenticationEntryPoint - implementation, which takes actions such as described in step - three. - - After your browser decides to submit your authentication - credentials (either as an HTTP form post or HTTP header) there needs to - be something on the server that "collects" these authentication - details. By now we're at step six in the above list. In Acegi Security - we have a special name for the function of collecting authentication - details from a user agent (usually a web browser), and that name is - "authentication mechanism". After the authentication details are - collected from the user agent, an "Authentication - request" object is built and then presented to an - AuthenticationProvider. - - The last played in the Acegi Security authentication process is - an AuthenticationProvider. Quite simply, it is - responsible for taking an Authentication request - object and deciding whether or not it is valid. The provider will - either throw an exception or return a fully populated - Authentication object. Remember our good friends, - UserDetails and - UserDetailsService? If not, head back to the - previous section and refresh your memory. Most - AuthenticationProviders will ask a - UserDetailsService to provide a - UserDetails object. As mentioned earlier, most - application will provide their own - UserDetailsService, although some will be able to - use the JDBC or in-memory implementation that ships with Acegi - Security. The resultant UserDetails object - and - particularly the GrantedAuthority[]s contained - within the UserDetails object - will be used when - building the fully populated Authentication - object. - - After the authentication mechanism receives back the - fully-populated Authentication object, it will deem - the request valid, put the Authentication into the - SecurityContextHolder, and cause the original - request to be retried (step seven above). If, on the other hand, the - AuthenticationProvider rejected the request, the - authentication mechanism will ask the user agent to retry (step two - above). - - Whilst this describes the typical authentication workflow, the - good news is that Acegi Security doesn't mind how you put an - Authentication inside the - SecurityContextHolder. The only critical - requirement is that the SecurityContextHolder - contains an Authentication that represents a - principal before the AbstractSecurityInterceptor - needs to authorize a request. - - You can (and many users do) write their own filters or MVC - controllers to provide interoperability with authentication systems - that are not based on Acegi Security. For example, you might be using - Container Managed Authentication which makes the current user - available from a ThreadLocal or JNDI location. Or you might work for a - company that has a legacy proprietary authentication system, which is - a corporate "standard" over which you have little control. In such - situations it's quite easy to get Acegi Security to work, and still - provide authorization capabilities. All you need to do is write a - filter (or equivalent) that reads the third-party user information - from a location, build an Acegi Security-specific Authentication - object, and put it onto the SecurityContextHolder. It's quite easy to - do this, and it is a fully-supported integration approach. - - - - Secure Objects - - If you're familiar with AOP, you'd be aware there are different - types of advice available: before, after, throws and around. An around - advice is very useful, because an advisor can elect whether or not to - proceed with a method invocation, whether or not to modify the - response, and whether or not to throw an exception. Acegi Security - provides an around advice for method invocations as well as web - requests. We achieve an around advice for method invocations using AOP - Alliance, and we achieve an around advice for web requests using a - standard Filter. - - For those not familiar with AOP, the key point to understand is - that Acegi Security can help you protect method invocations as well as - web requests. Most people are interested in securing method - invocations on their services layer. This is because the services - layer is where most business logic resides in current-generation J2EE - applications (for clarification, the author disapproves of this design - and instead advocates properly encapsulated domain objects together - with the DTO, assembly, facade and transparent persistence patterns, - but as anemic domain objects is the present mainstream approach, we'll - talk about it here). If you just need to secure method invocations to - the services layer, using the Spring's standard AOP platform - (otherwise known as AOP Alliance) will be adequate. If you need to - secure domain objects directly, you will likely find that AspectJ is - worth considering. - - You can elect to perform method authorization using AspectJ or - AOP Alliance, or you can elect to perform web request authorization - using filters. You can use zero, one, two or three of these approaches - together. The mainstream usage is to perform some web request - authorization, coupled with some AOP Alliance method invocation - authorization on the services layer. - - Acegi Security uses the term "secure object" to refer to any - object that can have security applied to it. Each secure object - supported by Acegi Security has its own class, which is a subclass of - AbstractSecurityInterceptor. Importantly, by the - time the AbstractSecurityInterceptor is run, the - SecurityContextHolder will contain a valid - Authentication if the principal has been - authenticated. - - The AbstractSecurityInterceptor provides a - consistent workflow for handling secure object requests. This workflow - includes looking up the "configuration attributes" associated with the - present request. A "configuration attribute" can be thought of as a - String that has special meaning to the classes used by - AbstractSecurityInterceptor. They're normally - configured against your AbstractSecurityInterceptor - using XML. Anyway, the AbstractSecurityInterceptor will ask an - AccessDecisionManager "here's the configuration - attributes, here's the current Authentication - object, and here's details of the current request - is this particular - principal allowed to perform this particular operation?". - - Assuming AccessDecisionManager decides to - allow the request, the AbstractSecurityInterceptor - will normally just proceed with the request. Having said that, on rare - occasions users may want to replace the - Authentication inside the - SecurityContext with a different - Authentication, which is handled by the - AccessDecisionManager calling a - RunAsManager. This might be useful in reasonably - unusual situations, such as if a services layer method needs to call a - remote system and present a different identity. Because Acegi Security - automatically propagates security identity from one server to another - (assuming you're using a properly-configured RMI or HttpInvoker - remoting protocol client), this may be useful. - - Following the secure object proceeding and then returning - - which may mean a method invocation completing or a filter chain - proceeding - the AbstractSecurityInterceptor gets - one final chance to handle the invocation. At this stage the - AbstractSecurityInterceptor is interested in - possibly modifying the return object. We might want this to happen - because an authorization decision couldn't be made "on the way in" to - a secure object invocation. Being highly pluggable, - AbstractSecurityInterceptor will pass control to an - AfterInvocationManager to actually modify the - object if needed. This class even can entirely replace the object, or - throw an exception, or not change it in any way. - - Because AbstractSecurityInterceptor is the - central template class, it seems fitting that the first figure should - be devoted to it. - - - - - - - - Figure 1: The key "secure object" model - - - - Only developers contemplating an entirely new way of - intercepting and authorizing requests would need to use secure objects - directly. For example, it would be possible to build a new secure - object to secure calls to a messaging system. Anything that requires - security and also provides a way of intercepting a call (like the AOP - around advice semantics) is capable of being made into a secure - object. Having said that, most Spring applications will simply use the - three currently supported secure object types (AOP Alliance - MethodInvocation, AspectJ - JoinPoint and web request - FilterInterceptor) with complete - transparency. - - - - Conclusion - - Congratulations! You have enough of a high-level picture of - Acegi Security to embark on your project. We've explored the shared - components, how authentication works, and reviewed the common - authorization concept of a "secure object". Everything that follows in - this reference guide may or may not apply to your particular needs, - and can be read in any order. - - - - - Supporting Infrastructure - - This chapter introduces some of the supplementary and supporting - infrastructure used by Acegi Security. If a capability is not directly - related to security, yet included in the Acegi Security project, we will - discuss it in this chapter. - - - Localization - - Acegi Security supports localization of exception messages that - end users are likely to see. If your application is designed for - English users, you don't need to do anything as by default all Acegi - Security messages are in English. If you need to support other - locales, everything you need to know is contained in this - section. - - All exception messages can be localized, including messages - related to authentication failures and access being denied - (authorization failures). Exceptions and logging that is focused on - developers or system deployers (including incorrect attributes, - interface contract violations, using incorrect constructors, startup - time validation, debug-level logging) etc are not localized and - instead are hard-coded in English within Acegi Security's code. - - Shipping in the acegi-security-xx.jar you - will find an org.acegisecurity package that in turn - contains a messages.properties file. This should be - referred to by your ApplicationContext, as Acegi - Security classes implement Spring's - MessageSourceAware interface and expect the message - resolver to be dependency injected at application context startup - time. Usually all you need to do is register a bean inside your - application context to refer to the messages. An example is shown - below: - - <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> - <property name="basename"><value>org/acegisecurity/messages</value></property> -</bean> - - The messages.properties is named in - accordance with standard resource bundles and represents the default - language supported by Acegi Securtiy messages. This default file is in - English. If you do not register a message source, Acegi Security will - still work correctly and fallback to hard-coded English versions of - the messages. - - If you wish to customize the - messages.properties file, or support other - languages, you should copy the file, rename it accordingly, and - register it inside the above bean definition. There are not a large - number of message keys inside this file, so localization should not be - considered a major initiative. If you do perform localization of this - file, please consider sharing your work with the community by logging - a JIRA task and attaching your appropriately-named localized version - of messages.properties. - - Rounding out the discussion on localization is the Spring - ThreadLocal known as - org.springframework.context.i18n.LocaleContextHolder. - You should set the LocaleContextHolder to represent - the preferred Locale of each user. Acegi Security - will attempt to locate a message from the message source using the - Locale obtained from this - ThreadLocal. Please refer to Spring documentation - for further details on using LocaleContextHolder - and the helper classes that can automatically set it for you (eg - AcceptHeaderLocaleResolver, - CookieLocaleResolver, - FixedLocaleResolver, - SessionLocaleResolver etc) - - - - Filters - - Acegi Security uses many filters, as referred to throughout the - remainder of this reference guide. You have a choice in how these - filters are added to your web application, in that you can use either - FilterToBeanProxy or - FilterChainProxy. We'll look at both below. - - Most filters are configured using the - FilterToBeanProxy. An example configuration from - web.xml follows: - - <filter> - <filter-name>Acegi HTTP Request Security Filter</filter-name> - <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class> - <init-param> - <param-name>targetClass</param-name> - <param-value>org.acegisecurity.ClassThatImplementsFilter</param-value> - </init-param> -</filter> - - Notice that the filter in web.xml is actually - a FilterToBeanProxy, and not the filter that will - actually implement the logic of the filter. What - FilterToBeanProxy does is delegate the - Filter's methods through to a bean which is - obtained from the Spring application context. This enables the bean to - benefit from the Spring application context lifecycle support and - configuration flexibility. The bean must implement - javax.servlet.Filter. - - The FilterToBeanProxy only requires a single - initialization parameter, targetClass or - targetBean. The targetClass - parameter locates the first object in the application context of the - specified class, whilst targetBean locates the - object by bean name. Like standard Spring web applications, the - FilterToBeanProxy accesses the application context - via - WebApplicationContextUtils.getWebApplicationContext(ServletContext), - so you should configure a ContextLoaderListener in - web.xml. - - There is a lifecycle issue to consider when hosting - Filters in an IoC container instead of a servlet - container. Specifically, which container should be responsible for - calling the Filter's "startup" and "shutdown" - methods? It is noted that the order of initialization and destruction - of a Filter can vary by servlet container, and this - can cause problems if one Filter depends on - configuration settings established by an earlier initialized - Filter. The Spring IoC container on the other hand - has more comprehensive lifecycle/IoC interfaces (such as - InitializingBean, - DisposableBean, BeanNameAware, - ApplicationContextAware and many others) as well as - a well-understood interface contract, predictable method invocation - ordering, autowiring support, and even options to avoid implementing - Spring interfaces (eg the destroy-method attribute - in Spring XML). For this reason we recommend the use of Spring - lifecycle services instead of servlet container lifecycle services - wherever possible. By default FilterToBeanProxy - will not delegate init(FilterConfig) and - destroy() methods through to the proxied bean. If - you do require such invocations to be delegated, set the - lifecycle initialization parameter to - servlet-container-managed. - - Rather than using FilterToBeanProxy, we - strongly recommend to use FilterChainProxy instead. - Whilst FilterToBeanProxy is a very useful class, - the problem is that the lines of code required for - <filter> and - <filter-mapping> entries in - web.xml explodes when using more than a few - filters. To overcome this issue, Acegi Security provides a - FilterChainProxy class. It is wired using a - FilterToBeanProxy (just like in the example above), - but the target class is - org.acegisecurity.util.FilterChainProxy. The filter - chain is then declared in the application context, using code such as - this: - - <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy"> - <property name="filterInvocationDefinitionSource"> - <value> - CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON - PATTERN_TYPE_APACHE_ANT - /webServices/**=httpSessionContextIntegrationFilterWithASCFalse,basicProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor - /**=httpSessionContextIntegrationFilterWithASCTrue,authenticationProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor - </value> - </property> -</bean> - - You may notice similarities with the way - FilterSecurityInterceptor is declared. Both regular - expressions and Ant Paths are supported, and the most specific URIs - appear first. At runtime the FilterChainProxy will - locate the first URI pattern that matches the current web request. - Each of the corresponding configuration attributes represent the name - of a bean defined in the application context. The filters will then be - invoked in the order they are specified, with standard - FilterChain behaviour being respected (a - Filter can elect not to proceed with the chain if - it wishes to end processing). - - As you can see, FilterChainProxy requires the - duplication of filter names for different request patterns (in the - above example, exceptionTranslationFilter and - filterSecurityInterceptor are duplicated). This - design decision was made to enable FilterChainProxy - to specify different Filter invocation orders for - different URI patterns, and also to improve both the expressiveness - (in terms of regular expressions, Ant Paths, and any custom - FilterInvocationDefinitionSource implementations) - and clarity of which Filters should be - invoked. - - You may have noticed we have declared two - HttpSessionContextIntegrationFilters in the filter - chain (ASC is short for - allowSessionCreation, a property of - HttpSessionContextIntegrationFilter). As web - services will never present a jsessionid on future - requests, creating HttpSessions for such user - agents would be wasteful. If you had a high-volume application which - required maximum scalability, we recommend you use the approach shown - above. For smaller applications, using a single - HttpSessionContextIntegrationFilter (with its - default allowSessionCreation as - true) would likely be sufficient. - - In relation to lifecycle issues, the - FilterChainProxy will always delegate - init(FilterConfig) and destroy() - methods through to the underlaying Filters if such - methods are called against FilterChainProxy itself. - In this case, FilterChainProxy guarantees to only - initialize and destroy each Filter once, - irrespective of how many times it is declared by the - FilterInvocationDefinitionSource. You control the - overall choice as to whether these methods are called or not via the - lifecycle initialization parameter of the - FilterToBeanProxy that proxies - FilterChainProxy. As discussed above, by default - any servlet container lifecycle invocations are not delegated through - to FilterChainProxy. - - You can also omit a URI pattern from the filter chain by using - the token #NONE# on the right-hand side of the - <URI Pattern> = <Filter Chain> expression. For example, using - the example above, if you wanted to exclude the /webservices - location completely, you would modify the corresponding line in the bean declaration to be - -/webServices/**=#NONE# - - Note that anything matching this path will then have no authentication - or authorization services applied and will be freely accessible. - - - - The order that filters are defined in web.xml - is very important. Irrespective of which filters you are actually - using, the order of the <filter-mapping>s - should be as follows: - - - - ChannelProcessingFilter, because it might - need to redirect to a different protocol - - - - ConcurrentSessionFilter, because it - doesn't use any SecurityContextHolder - functionality but needs to update the - SessionRegistry to reflect ongoing requests - from the principal - - - - HttpSessionContextIntegrationFilter, so a - SecurityContext can be setup in the - SecurityContextHolder at the beginning of a web - request, and any changes to the SecurityContext - can be copied to the HttpSession when the web - request ends (ready for use with the next web request) - - - - Authentication processing mechanisms - - AuthenticationProcessingFilter, - CasProcessingFilter, - BasicProcessingFilter, HttpRequestIntegrationFilter, - JbossIntegrationFilter etc - so that the - SecurityContextHolder can be modified to - contain a valid Authentication request - token - - - - The - SecurityContextHolderAwareRequestFilter, if you - are using it to install an Acegi Security aware - HttpServletRequestWrapper into your servlet - container - - - - RememberMeProcessingFilter, so that if no - earlier authentication processing mechanism updated the - SecurityContextHolder, and the request presents - a cookie that enables remember-me services to take place, a - suitable remembered - Authentication object will - be put there - - - - AnonymousProcessingFilter, so that if no - earlier authentication processing mechanism updated the - SecurityContextHolder, an anonymous - Authentication object will be put there - - - - ExceptionTranslationFilter, to catch any - Acegi Security exceptions so that either an HTTP error response can - be returned or an appropriate - AuthenticationEntryPoint can be launched - - - - FilterSecurityInterceptor, to protect web - URIs - - - - All of the above filters use - FilterToBeanProxy or - FilterChainProxy. It is recommended that a single - FilterToBeanProxy proxy through to a single - FilterChainProxy for each application, with that - FilterChainProxy defining all of Acegi Security - Filters. - - If you're using SiteMesh, ensure Acegi Security filters execute - before the SiteMesh filters are called. This enables the - SecurityContextHolder to be populated in time for - use by SiteMesh decorators - - - - - Channel Security - - - Overview - - In addition to coordinating the authentication and authorization - requirements of your application, Acegi Security is also able to - ensure unauthenticated web requests have certain properties. These - properties may include being of a particular transport type, having a - particular HttpSession attribute set and so on. The - most common requirement is for your web requests to be received using - a particular transport protocol, such as HTTPS. - - An important issue in considering transport security is that of - session hijacking. Your web container manages a - HttpSession by reference to a - jsessionid that is sent to user agents either via a - cookie or URL rewriting. If the jsessionid is ever - sent over HTTP, there is a possibility that session identifier can be - intercepted and used to impersonate the user after they complete the - authentication process. This is because most web containers maintain - the same session identifier for a given user, even after they switch - from HTTP to HTTPS pages. - - If session hijacking is considered too significant a risk for - your particular application, the only option is to use HTTPS for every - request. This means the jsessionid is never sent - across an insecure channel. You will need to ensure your - web.xml-defined - <welcome-file> points to an HTTPS location, - and the application never directs the user to an HTTP location. Acegi - Security provides a solution to assist with the latter. - - - - Configuration - - To utilise Acegi Security's channel security services, add the - following lines to web.xml: - - -<filter> - <filter-name>Acegi Channel Processing Filter</filter-name> - <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class> - <init-param> - <param-name>targetClass</param-name> - <param-value>org.acegisecurity.securechannel.ChannelProcessingFilter</param-value> - </init-param> -</filter> - -<filter-mapping> - <filter-name>Acegi Channel Processing Filter</filter-name> - <url-pattern>/*</url-pattern> -</filter-mapping> - - - - As usual when running FilterToBeanProxy, you - will also need to configure the filter in your application - context: - - -<bean id="channelProcessingFilter" class="org.acegisecurity.securechannel.ChannelProcessingFilter"> - <property name="channelDecisionManager"><ref bean="channelDecisionManager"/></property> - <property name="filterInvocationDefinitionSource"> - <value> - CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON - \A/secure/.*\Z=REQUIRES_SECURE_CHANNEL - \A/acegilogin.jsp.*\Z=REQUIRES_SECURE_CHANNEL - \A/j_acegi_security_check.*\Z=REQUIRES_SECURE_CHANNEL - \A.*\Z=REQUIRES_INSECURE_CHANNEL - </value> - </property> -</bean> - -<bean id="channelDecisionManager" class="org.acegisecurity.securechannel.ChannelDecisionManagerImpl"> - <property name="channelProcessors"> - <list> - <ref bean="secureChannelProcessor"/> - <ref bean="insecureChannelProcessor"/> - </list> - </property> -</bean> - -<bean id="secureChannelProcessor" class="org.acegisecurity.securechannel.SecureChannelProcessor"/> -<bean id="insecureChannelProcessor" class="org.acegisecurity.securechannel.InsecureChannelProcessor"/> - - - - Like FilterSecurityInterceptor, Apache Ant - style paths are also supported by the - ChannelProcessingFilter. - - The ChannelProcessingFilter operates by - filtering all web requests and determining the configuration - attributes that apply. It then delegates to the - ChannelDecisionManager. The default implementation, - ChannelDecisionManagerImpl, should suffice in most - cases. It simply delegates through the list of configured - ChannelProcessor instances. A - ChannelProcessor will review the request, and if it - is unhappy with the request (eg it was received across the incorrect - transport protocol), it will perform a redirect, throw an exception or - take whatever other action is appropriate. - - Included with Acegi Security are two concrete - ChannelProcessor implementations: - SecureChannelProcessor ensures requests with a - configuration attribute of REQUIRES_SECURE_CHANNEL - are received over HTTPS, whilst - InsecureChannelProcessor ensures requests with a - configuration attribute of - REQUIRES_INSECURE_CHANNEL are received over HTTP. - Both implementations delegate to a - ChannelEntryPoint if the required transport - protocol is not used. The two ChannelEntryPoint - implementations included with Acegi Security simply redirect the - request to HTTP and HTTPS as appropriate. Appropriate defaults are - assigned to the ChannelProcessor implementations - for the configuration attribute keywords they respond to and the - ChannelEntryPoint they delegate to, although you - have the ability to override these using the application - context. - - Note that the redirections are absolute (eg - http://www.company.com:8080/app/page), not relative - (eg /app/page). During testing it was discovered - that Internet Explorer 6 Service Pack 1 has a bug whereby it does not - respond correctly to a redirection instruction which also changes the - port to use. Accordingly, absolute URLs are used in conjunction with - bug detection logic in the PortResolverImpl that is - wired up by default to many Acegi Security beans. Please refer to the - JavaDocs for PortResolverImpl for further - details. - - You should note that using a secure channel is recommended if - usernames and passwords are to be kept secure during the login - process. If you do decide to use - ChannelProcessingFilter with form-based login, - please ensure that your login page is set to - REQUIRES_SECURE_CHANNEL, and that the - AuthenticationProcessingFilterEntryPoint.forceHttps - property is true. - - - - Conclusion - - Once configured, using the channel security filter is very easy. - Simply request pages without regard to the protocol (ie HTTP or HTTPS) - or port (eg 80, 8080, 443, 8443 etc). Obviously you'll still need a - way of making the initial request (probably via the - web.xml <welcome-file> or - a well-known home page URL), but once this is done the filter will - perform redirects as defined by your application context. - - You can also add your own ChannelProcessor - implementations to the ChannelDecisionManagerImpl. - For example, you might set a HttpSession attribute - when a human user is detected via a "enter the contents of this - graphic" procedure. Your ChannelProcessor would - respond to say REQUIRES_HUMAN_USER configuration - attributes and redirect to an appropriate entry point to start the - human user validation process if the HttpSession - attribute is not currently set. - - To decide whether a security check belongs in a - ChannelProcessor or an - AccessDecisionVoter, remember that the former is - designed to handle unauthenticated requests, whilst the latter is - designed to handle authenticated requests. The latter therefore has - access to the granted authorities of the authenticated principal. In - addition, problems detected by a ChannelProcessor - will generally cause an HTTP/HTTPS redirection so its requirements can - be met, whilst problems detected by an - AccessDecisionVoter will ultimately result in an - AccessDeniedException (depending on the governing - AccessDecisionManager). - - - - - Tag Libraries - - - Overview - - Acegi Security comes bundled with several JSP tag libraries that - eases JSP writing. The tag libraries are known as - authz and provide a range of different - services. - - - - Configuration - - All taglib classes are included in the core - acegi-security-xx.jar file, with the - authz.tld located in the JAR's - META-INF directory. This means for JSP 1.2+ web - containers you can simply include the JAR in the WAR's - WEB-INF/lib directory and it will be available. If - you're using a JSP 1.1 container, you'll need to declare the JSP - taglib in your web.xml file, and include - authz.tld in the WEB-INF/lib - directory. The following fragment is added to - web.xml: - - <taglib> - <taglib-uri>http://acegisecurity.org/authz</taglib-uri> - <taglib-location>/WEB-INF/authz.tld</taglib-location> -</taglib> - - - - Usage - - Now that you've configured the tag libraries, refer to the - individual reference guide sections for details on how to use - them. - - - - - - Authentication - - - In this part of the reference guide we will examine individual - authentication mechanisms and their corresponding - AuthenticationProviders. We'll also look at how to - configure authentication more generally, including if you have several - authentication approaches that need to be chained together. - - - - Common Authentication Services - - - Mechanisms, Providers and Entry Points - - If you're using Acegi Security-provided authentication - approaches, you'll usually need to configure a web filter, together - with an AuthenticationProvider and - AuthenticationEntryPoint. In this section we are - going to explore an example application that needs to support both - form-based authentication (ie so a nice HTML page is presented to a - user for them to login) plus BASIC authentication (ie so a web service - or similar can access protected resources). - - In the web.xml, this application will need a single Acegi - Security filter in order to use the FilterChainProxy. Nearly every - Acegi Security application will have such an entry, and it looks like - this: - - <filter> - <filter-name>Acegi Filter Chain Proxy</filter-name> - <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class> - <init-param> - <param-name>targetClass</param-name> - <param-value>org.acegisecurity.util.FilterChainProxy</param-value> - </init-param> -</filter> - -<filter-mapping> - <filter-name>Acegi Filter Chain Proxy</filter-name> - <url-pattern>/*</url-pattern> -</filter-mapping> - - The above declarations will cause every web request to be passed - through to Acegi Security's FilterChainProxy. As explained in the - filters section of this reference guide, the FilterChainProxy is a - generally-useful class that enables web requests to be passed to - different filters based on the URL patterns. Those delegated filters - are managed inside the application context, so they can benefit from - dependency injection. Let's have a look at what the FilterChainProxy - bean definition would look like inside your application - context: - - <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy"> - <property name="filterInvocationDefinitionSource"> - <value> - CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON - PATTERN_TYPE_APACHE_ANT - /**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,basicProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor,switchUserProcessingFilter - </value> - </property> -</bean> - - Internally Acegi Security will use a - PropertyEditor to convert the string presented in - the above XML fragment into a - FilterInvocationDefinitionSource object. What's - important to note at this stage is that a series of filters will be - run - in the order specified by the declaration - and each of those - filters are actually the <bean id> of another - bean inside the application context. So, in our case some extra beans - will also appear in the application context, and they'll be named - httpSessionContextIntegrationFilter, - logoutFilter and so on. The order that the filters - should appear is discussed in the filters section of the reference - guide - although they are correct in the above example. - - In our example we have the - AuthenticationProcessingFilter and - BasicProcessingFilter being used. These are the - "authentication mechanisms" that respond to form-based authentication - and BASIC HTTP header-based authentication respectively (we discussed - the role of authentication mechanisms earlier in this reference - guide). If you weren't using form or BASIC authentication, neither of - these beans would be defined. You'd instead define filters applicable - to your desired authentication environment, such as - DigestProcessingFilter or - CasProcessingFilter. Refer to the individual - chapters of this part of the reference guide to learn how to configure - each of these authentication mechanisms. - - Recall that - HttpSessionContextIntegrationFilter keeps the - contents of the SecurityContext between invocations - inside an HTTP session. This means the authentication mechanisms are - only used once, being when the principal initially tries to - authenticate. The rest of the time the authentication mechanisms sit - there and silently pass the request through to the next filter in the - chain. That is a practical requirement due to the fact that few - authentication approaches present credentials on each and every call - (BASIC authentication being a notable exception), but what happens if - a principal's account gets cancelled or disabled or otherwise changed - (eg an increase or decrease in GrantedAuthority[]s) - after the initial authentication step? Let's look at how that is - handled now. - - The major authorization provider for secure objects has - previously been introduced as - AbstractSecurityInterceptor. This class needs to - have access to an AuthenticationManager. It also - has configurable settings to indicate whether an - Authentication object should be re-authenticated on - each secure object invocation. By default it just accepts any - Authentication inside the - SecurityContextHolder is authenticated if - Authentication.isAuthenticated() returns true. This - is great for performance, but not ideal if you want to ensure - up-to-the-moment authentication validity. For such cases you'll - probably want to set the - AbstractSecurityInterceptor.alwaysReauthenticate - property to true. - - You might be asking yourself, "what's this - AuthenticationManager?". We haven't explored it - before, but we have discussed the concept of an - AuthenticationProvider. Quite simply, an - AuthenticationManager is responsible for passing requests through a - chain of AuthenticationProviders. It's a little like the filter chain - we discussed earlier, although there are some differences. There is - only one AuthenticationManager implementation shipped with Acegi - Security, so let's look at how it's configured for the example we're - using in this chapter: - - <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"> - <property name="providers"> - <list> - <ref local="daoAuthenticationProvider"/> - <ref local="anonymousAuthenticationProvider"/> - <ref local="rememberMeAuthenticationProvider"/> - </list> - </property> -</bean> - - It's probably worth mentioning at this point that your - authentication mechanisms (which are usually filters) are also - injected with a reference to the - AuthenticationManager. So both - AbstractSecurityInterceptor as well as the - authentication mechanisms will use the above - ProviderManager to poll a list of - AuthenticationProviders. - - In our example we have three providers. They are tried in the - order shown (which is implied by the use of a List - instead of a Set), with each provider able to - attempt authentication, or skip authentication by simply returning - null. If all implementations return null, the - ProviderManager will throw a suitable exception. If - you're interested in learning more about chaining providers, please - refer to the ProviderManager JavaDocs. - - The providers to use will sometimes be interchangeable with the - authentication mechanisms, whilst at other times they will depend on a - specific authentication mechanism. For example, the - DaoAuthenticationProvider just needs a string-based - username and password. Various authentication mechanisms result in the - collection of a string-based username and password, including (but not - limited to) BASIC and form authentication. Equally, some - authentication mechanisms create an authentication request object - which can only be interpreted by a single type of - AuthenticationProvider. An example of this - one-to-one mapping would be JA-SIG CAS, which uses the notion of a - service ticket which can therefore only be authenticated by - CasAuthenticationProvider. A further example of a - one-to-one mapping would be the LDAP authentication mechanism, which - can only be processed an the - LdapAuthenticationProvider. The specifics of such - relationships are detailed in the JavaDocs for each class, plus the - authentication approach-specific chapters of this reference guide. You - need not be terribly concerned about this implementation detail, - because if you forget to register a suitable provider, you'll simply - receive a ProviderNotFoundException when an attempt - to authenticate is made. - - After configuring the correct authentication mechanisms in the - FilterChainProxy, and ensuring that a corresponding - AuthenticationProvider is registered in the - ProviderManager, your last step is to configure an - AuthenticationEntryPoint. Recall that earlier we - discussed the role of ExceptionTranslationFilter, - which is used when HTTP-based requests should receive back an HTTP - header or HTTP redirect in order to start authentication. Continuing - on with our earlier example: - - <bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter"> - <property name="authenticationEntryPoint"><ref local="authenticationProcessingFilterEntryPoint"/></property> - <property name="accessDeniedHandler"> - <bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl"> - <property name="errorPage" value="/accessDenied.jsp"/> - </bean> - </property> -</bean> - -<bean id="authenticationProcessingFilterEntryPoint" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint"> - <property name="loginFormUrl"><value>/acegilogin.jsp</value></property> - <property name="forceHttps"><value>false</value></property> -</bean> - - Notice that the ExceptionTranslationFilter - requires two collaborators. The first, - AccessDeniedHandlerImpl, uses a - RequestDispatcher forward to display the specified - access denied error page. We use a forward so that the - SecurityContextHolder still contains details of the - principal, which may be useful for display to the user (in old - releases of Acegi Security we relied upon the servlet container to - handle a 403 error message, which lacked this useful contextual - information). AccessDeniedHandlerImpl will also set - the HTTP header to 403, which is the official error code to indicate - access denied. In the case of the - AuthentionEntryPoint, here we're setting what - action we would like taken when an unauthenticated principal attempts - to perform a protected operation. Because in our example we're going - to be using form-based authentication, we specify - AuthenticationProcessinFilterEntryPoint and the URL - of the login page. Your application will usually only have one entry - point, and most authentication approaches define their own specific - AuthenticationEntryPoint. Details of which entry - point to use for each authentication approach is discussed in the - authentication approach-specific chapters of this reference - guide. - - - - UserDetails and Associated Types - - As mentioned in the first part of the reference guide, most - authentication providers take advantage of the - UserDetails and - UserDetailsService interfaces. The contract for - this latter interface consists of a single method: - - public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException; - - The returned UserDetails is an interface that - provides getters that guarantee non-null provision of basic - authentication information such as the username, password, granted - authorities and whether the user is enabled or disabled. Most - authentication providers will use a - UserDetailsService, even if the username and - password are not actually used as part of the authentication decision. - Generally such provider will be using the returned - UserDetails object just for its - GrantedAuthority[] information, because some other - system (like LDAP or X509 or CAS etc) has undertaken the - responsibility of actually validating the credentials. - - A single concrete implementation of - UserDetails is provided with Acegi Security, being - the User class. Acegi Security users will need to - decide when writing their UserDetailsService what - concrete UserDetails class to return. In most cases - User will be used directly or subclassed, although - special circumstances (such as object relational mappers) may require - users to write their own UserDetails implementation - from scratch. This is not such an unusual situation, and users should - not hesitate to simply return their normal domain object that - represents a user of the system. This is especially common given that - UserDetails is often used to store additional - principal-related properties (such as their telephone number and email - address), so that they can be easily used by web views. - - Given UserDetailsService is so simple to - implement, it should be easy for users to retrieve authentication - information using a persistence strategy of their choice. Having said - that, Acegi Security does include a couple of useful base - implementations, which we'll look at below. - - - In-Memory Authentication - - Whilst it is easy to use create a custom - UserDetailsService implementation that extracts - information from a persistence engine of choice, many applications - do not require such complexity. This is particularly true if you're - undertaking a rapid prototype or just starting integrating Acegi - Security, when you don't really want to spend time configuring - databases or writing UserDetailsService - implementations. For this sort of situation, a simple option is to - configure the InMemoryDaoImpl - implementation: - - <bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.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> - - In the above example, the userMap property - contains each of the usernames, passwords, a list of granted - authorities and an optional enabled/disabled keyword. Commas are - used to delimit each token. The username must appear to the left of - the equals sign, and the password must be the first token to the - right of the equals sign. The enabled and - disabled keywords (case insensitive) may appear - in the second or any subsequent token. Any remaining tokens are - treated as granted authorities, which are created as - GrantedAuthorityImpl objects (this is just for - your reference - most applications don't need custom - GrantedAuthority implementations, so using the - default implementation in this manner is just fine). Note that if a - user has no password and/or no granted authorities, the user will - not be created in the in-memory authentication repository. - - InMemoryDaoImpl also offers a - setUserProperties(Properties) method, which - allows you to externalise the - java.util.Properties in another Spring configured - bean or an external properties file. You might like to use Spring's - PropertiesFactoryBean, which is useful for - loading such external properties files. This setter might prove - useful for simple applications that have a larger number of users, - or deployment-time configuration changes, but do not wish to use a - full database for handling authentication details. - - - - JDBC Authentication - - Acegi Security also includes a - UserDetailsService that can obtain authentication - information from a JDBC data source. Internally Spring JDBC is used, - so it avoids the complexity of a fully-featured object relational - mapper (ORM) just to store user details. If your application does - use an ORM tool, you might prefer to write a custom - UserDetailsService to reuse the mapping files - you've probably already created. Returning to - JdbcDaoImpl, an example configuration is shown - below: - - <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> - <property name="driverClassName"><value>org.hsqldb.jdbcDriver</value></property> - <property name="url"><value>jdbc:hsqldb:hsql://localhost:9001</value></property> - <property name="username"><value>sa</value></property> - <property name="password"><value></value></property> -</bean> - -<bean id="jdbcDaoImpl" class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl"> - <property name="dataSource"><ref bean="dataSource"/></property> -</bean> - - You can use different relational database management systems - by modifying the DriverManagerDataSource shown - above. You can also use a global data source obtained from JNDI, as - per normal Spring options. Irrespective of the database used and how - a DataSource is obtained, a standard schema must - be used as indicated in dbinit.txt. You can - download this file from the Acegi Security web site. - - If your default schema is unsuitable for your needs, - JdbcDaoImpl provides two properties that allow - customisation of the SQL statements. You may also subclass the - JdbcDaoImpl if further customisation is - necessary. Please refer to the JavaDocs for details, although please - note that the class is not intended for complex custom subclasses. - If you have complex needs (such as a special schema or would like a - certain UserDetails implementation returned), - you'd be better off writing your own - UserDetailsService. The base implementation - provided with Acegi Security is intended for typical situations, and - does not offer infinite configuration flexibility. - - - - - Concurrent Session Handling - - Acegi Security is able to prevent a principal from concurrently - authenticating to the same application more than a specified number of - times. Many ISVs take advantage of this to enforce licensing, whilst - network administrators like this feature because it helps prevent - people from sharing login names. You can, for example, stop user - "Batman" from logging onto the web application from two different - sessions. - - To use concurrent session support, you'll need to add the - following to web.xml: - - <listener> - <listener-class>org.acegisecurity.ui.session.HttpSessionEventPublisher</listener-class> -</listener> - - In addition, you will need to add the - org.acegisecurity.concurrent.ConcurrentSessionFilter - to your FilterChainProxy. The - ConcurrentSessionFilter requires two properties, - sessionRegistry, which generally points to an - instance of SessionRegistryImpl, and - expiredUrl, which points to the page to display - when a session has expired. - - The web.xml - HttpSessionEventPublisher causes an - ApplicationEvent to be published to the Spring - ApplicationContext every time a - HttpSession commences or terminates. This is - critical, as it allows the SessionRegistryImpl to - be notified when a session ends. - - You will also need to wire up the - ConcurrentSessionControllerImpl and refer to it - from your ProviderManager bean: - - <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"> - <property name="providers"> - <!-- your providers go here --> - </property> - <property name="sessionController"><ref bean="concurrentSessionController"/></property> -</bean> - -<bean id="concurrentSessionController" class="org.acegisecurity.concurrent.ConcurrentSessionControllerImpl"> - <property name="maximumSessions"><value>1</value></property> - <property name="sessionRegistry"><ref local="sessionRegistry"/></property> -</bean> - -<bean id="sessionRegistry" class="org.acegisecurity.concurrent.SessionRegistryImpl"/> - - - - Authentication Tag Libraries - - AuthenticationTag is used to simply output a - property of the current principal's - Authentication.getPrincipal() object to the web - page. - - The following JSP fragment illustrates how to use the - AuthenticationTag: - - <authz:authentication operation="username"/> - - This tag would cause the principal's name to be output. Here we - are assuming the Authentication.getPrincipal() is a - UserDetails object, which is generally the case - when using the typical - DaoAuthenticationProvider. - - - - - DAO Authentication Provider - - - Overview - - Acegi Security includes a production-quality - AuthenticationProvider implementation called - DaoAuthenticationProvider. This authentication - provider is compatible with all of the authentication mechanisms that - generate a UsernamePasswordAuthenticationToken, and - is probably the most commonly used provider in the framework. Like - most of the other authentication providers, the - DaoAuthenticationProvider leverages a UserDetailsService in order to - lookup the username, password and GrantedAuthority[]s. Unlike most of - the other authentication providers that leverage UserDetailsService, - this authentication provider actually requires the password to be - presented, and the provider will actually evaluate the validity or - otherwise of the password presented in an authentication request - object. - - - - Configuration - - Aside from adding DaoAuthenticationProvider to your - ProviderManager list (as discussed at the start of this part of the - reference guide), and ensuring a suitable authentication mechanism is - configured to present a UsernamePasswordAuthenticationToken, the - configuration of the provider itself is rather simple: - - <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"> - <property name="userDetailsService"><ref bean="inMemoryDaoImpl"/></property> - <property name="saltSource"><ref bean="saltSource"/></property> - <property name="passwordEncoder"><ref bean="passwordEncoder"/></property> -</bean> - - The PasswordEncoder and - SaltSource are optional. A - PasswordEncoder provides encoding and decoding of - passwords presented in the UserDetails object that - is returned from the configured UserDetailsService. - A SaltSource enables the passwords to be populated - with a "salt", which enhances the security of the passwords in the - authentication repository. PasswordEncoder - implementations are provided with Acegi Security covering MD5, SHA and - cleartext encodings. Two SaltSource implementations - are also provided: SystemWideSaltSource which - encodes all passwords with the same salt, and - ReflectionSaltSource, which inspects a given - property of the returned UserDetails object to - obtain the salt. Please refer to the JavaDocs for further details on - these optional features. - - In addition to the properties above, the - DaoAuthenticationProvider supports optional caching - of UserDetails objects. The - UserCache interface enables the - DaoAuthenticationProvider to place a - UserDetails object into the cache, and retrieve it - from the cache upon subsequent authentication attempts for the same - username. By default the DaoAuthenticationProvider - uses the NullUserCache, which performs no caching. - A usable caching implementation is also provided, - EhCacheBasedUserCache, which is configured as - follows: - - <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"> - <property name="userDetailsService"><ref bean="userDetailsService"/></property> - <property name="userCache"><ref bean="userCache"/></property> -</bean> - -<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> - <property name="configLocation"> - <value>classpath:/ehcache-failsafe.xml</value> - </property> -</bean> - -<bean id="userCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean"> - <property name="cacheManager"> - <ref local="cacheManager"/> - </property> - <property name="cacheName"> - <value>userCache</value> - </property> -</bean> - -<bean id="userCache" class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache"> - <property name="cache"><ref local="userCacheBackend"/></property> -</bean> - - All Acegi Security EH-CACHE implementations (including - EhCacheBasedUserCache) require an EH-CACHE - Cache object. The Cache object - can be obtained from wherever you like, although we recommend you use - Spring's factory classes as shown in the above configuration. If using - Spring's factory classes, please refer to the Spring documentation for - further details on how to optimise the cache storage location, memory - usage, eviction policies, timeouts etc. - - A design decision was made not to support account locking in the - DaoAuthenticationProvider, as doing so would have - increased the complexity of the UserDetailsService - interface. For instance, a method would be required to increase the - count of unsuccessful authentication attempts. Such functionality - could be easily provided by leveraging the application event - publishing features discussed below. - - DaoAuthenticationProvider returns an - Authentication object which in turn has its - principal property set. The principal will be - either a String (which is essentially the username) - or a UserDetails object (which was looked up from - the UserDetailsService). By default the - UserDetails is returned, as this enables - applications to add extra properties potentially of use in - applications, such as the user's full name, email address etc. If - using container adapters, or if your applications were written to - operate with Strings (as was the case for releases - prior to Acegi Security 0.6), you should set the - DaoAuthenticationProvider.forcePrincipalAsString - property to true in your application context - - - - - Java Authentication and Authorization Service (JAAS) - Provider - - - Overview - - Acegi Security provides a package able to delegate - authentication requests to the Java Authentication and Authorization - Service (JAAS). This package is discussed in detail below. - - Central to JAAS operation are login configuration files. To - learn more about JAAS login configuration files, consult the JAAS - reference documentation available from Sun Microsystems. We expect you - to have a basic understanding of JAAS and its login configuration file - syntax in order to understand this section. - - - - Configuration - - The JaasAuthenticationProvider attempts to - authenticate a user’s principal and credentials through JAAS. - - Let’s assume we have a JAAS login configuration file, - /WEB-INF/login.conf, with the following - contents: - - JAASTest { - sample.SampleLoginModule required; -}; - - Like all Acegi Security beans, the - JaasAuthenticationProvider is configured via the - application context. The following definitions would correspond to the - above JAAS login configuration file: - - -<bean id="jaasAuthenticationProvider" class="org.acegisecurity.providers.jaas.JaasAuthenticationProvider"> - <property name="loginConfig"> - <value>/WEB-INF/login.conf</value> - </property> - <property name="loginContextName"> - <value>JAASTest</value> - </property> - <property name="callbackHandlers"> - <list> - <bean class="org.acegisecurity.providers.jaas.JaasNameCallbackHandler"/> - <bean class="org.acegisecurity.providers.jaas.JaasPasswordCallbackHandler"/> - </list> - </property> - <property name="authorityGranters"> - <list> - <bean class="org.acegisecurity.providers.jaas.TestAuthorityGranter"/> - </list> - </property> -</bean> - - - - The CallbackHandlers and - AuthorityGranters are discussed below. - - - JAAS CallbackHandler - - Most JAAS LoginModules require a callback - of some sort. These callbacks are usually used to obtain the - username and password from the user. - - In an Acegi Security deployment, Acegi Security is responsible - for this user interaction (via the authentication mechanism). Thus, - by the time the authentication request is delegated through to JAAS, - Acegi Security's authentication mechanism will already have - fully-populated an Authentication object - containing all the information required by the JAAS - LoginModule. - - Therefore, the JAAS package for Acegi Security provides two - default callback handlers, - JaasNameCallbackHandler and - JaasPasswordCallbackHandler. Each of these - callback handlers implement - JaasAuthenticationCallbackHandler. In most cases - these callback handlers can simply be used without understanding the - internal mechanics. - - For those needing full control over the callback behavior, - internally JaasAutheticationProvider wraps these - JaasAuthenticationCallbackHandlers with an - InternalCallbackHandler. The - InternalCallbackHandler is the class that - actually implements JAAS’ normal CallbackHandler - interface. Any time that the JAAS LoginModule is - used, it is passed a list of application context configured - InternalCallbackHandlers. If the - LoginModule requests a callback against the - InternalCallbackHandlers, the callback is in-turn - passed to the JaasAuthenticationCallbackHandlers - being wrapped. - - - - JAAS AuthorityGranter - - JAAS works with principals. Even "roles" are represented as - principals in JAAS. Acegi Security, on the other hand, works with - Authentication objects. Each - Authentication object contains a single - principal, and multiple GrantedAuthority[]s. To - facilitate mapping between these different concepts, Acegi - Security's JAAS package includes an - AuthorityGranter interface. - - An AuthorityGranter is responsible for - inspecting a JAAS principal and returning a - String. The - JaasAuthenticationProvider then creates a - JaasGrantedAuthority (which implements Acegi - Security’s GrantedAuthority interface) containing - both the AuthorityGranter-returned - String and the JAAS principal that the - AuthorityGranter was passed. The - JaasAuthenticationProvider obtains the JAAS - principals by firstly successfully authenticating the user’s - credentials using the JAAS LoginModule, and then - accessing the LoginContext it returns. A call to - LoginContext.getSubject().getPrincipals() is - made, with each resulting principal passed to each - AuthorityGranter defined against the - JaasAuthenticationProvider.setAuthorityGranters(List) - property. - - Acegi Security does not include any production - AuthorityGranters given that every JAAS principal - has an implementation-specific meaning. However, there is a - TestAuthorityGranter in the unit tests that - demonstrates a simple AuthorityGranter - implementation. - - - - - - Siteminder Authentication Mechanism - - - Overview - - Siteminder is a commercial single sign on solution by Computer - Associates. - - Acegi Security provides a filter, - SiteminderAuthenticationProcessingFilter and - provider, SiteminderAuthenticationProvider that can - be used to process requests that have been pre-authenticated by - Siteminder. This filter assumes that you're using Siteminder for - authentication, and that you're using Acegi - Security for authorization. The use of Siteminder - for authorization is not yet directly supported - by Acegi Security. - - When using Siteminder, an agent is setup on your web server to - intercept a principal's first call to your application. The agent - redirects the web request to a single sign-on login page, and once - authenticated, your application receives the request. Inside the HTTP - request is a header - such as SM_USER - which - identifies the authenticated principal (please refer to your - organization's "single sign-on" group for header details in your - particular configuration). - - - - Configuration - - The first step in setting up Acegi Security's Siteminder support - is to define the authentication mechanism that will inspect the HTTP - header discussed earlier. It will be responsible for generating a - UsernamePasswordAuthenticationToken that is later - sent to the SiteminderAuthenticationProvider. Let's - look at an example: - - <bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.SiteminderAuthenticationProcessingFilter"> - <property name="authenticationManager"><ref bean="authenticationManager"/></property> - <property name="authenticationFailureUrl"><value>/login.jsp?login_error=1</value></property> - <property name="defaultTargetUrl"><value>/security.do?method=getMainMenu</value></property> - <property name="filterProcessesUrl"><value>/j_acegi_security_check</value></property> - <property name="siteminderUsernameHeaderKey"><value>SM_USER</value></property> - <property name="formUsernameParameterKey"><value>j_username</value></property> -</bean> - - In our example above, the bean is being provided an - AuthenticationManager, as is normally needed by - authentication mechanisms. Several URLs are also specified, with the - values being self-explanatory. It's important to also specify the HTTP - header that Acegi Security should inspect. If you additionally want to - support form-based authentication (i.e. in your development - environment where Siteminder is not installed), specify the form's - username parameter as well - just don't do this in production! - - Note that you'll need a - SiteminderAuthenticationProvider - configured against your ProviderManager in order to - use the Siteminder authentication mechanism. Normally an - AuthenticationProvider expects the password - property to match what it retrieves from the - UserDetailsSource, but in this case, authentication - has already been handled by Siteminder, so password property is not - even relevant. This may sound like a security weakness, but remember - that users have to authenticate with Siteminder before your - application ever receives the requests, so the purpose of your custom - UserDetailsService should simply be to build the - complete Authentication object (ie with suitable - GrantedAuthority[]s). - - Advanced tip and word to the wise: If you additionally want to - support form-based authentication in your development environment - (where Siteminder is typically not installed), specify the form's - username parameter as well. Just don't do this in production! - - - - - Run-As Authentication Replacement - - - Overview - - The AbstractSecurityInterceptor is able to - temporarily replace the Authentication object in - the SecurityContext and - SecurityContextHolder during the secure object - callback phase. This only occurs if the original - Authentication object was successfully processed by - the AuthenticationManager and - AccessDecisionManager. The - RunAsManager will indicate the replacement - Authentication object, if any, that should be used - during the SecurityInterceptorCallback. - - By temporarily replacing the Authentication - object during the secure object callback phase, the secured invocation - will be able to call other objects which require different - authentication and authorization credentials. It will also be able to - perform any internal security checks for specific - GrantedAuthority objects. Because Acegi Security - provides a number of helper classes that automatically configure - remoting protocols based on the contents of the - SecurityContextHolder, these run-as replacements - are particularly useful when calling remote web services - - - - Configuration - - A RunAsManager interface is provided by Acegi - Security: - - public Authentication buildRunAs(Authentication authentication, Object object, ConfigAttributeDefinition config); -public boolean supports(ConfigAttribute attribute); -public boolean supports(Class clazz); - - The first method returns the Authentication - object that should replace the existing - Authentication object for the duration of the - method invocation. If the method returns null, it - indicates no replacement should be made. The second method is used by - the AbstractSecurityInterceptor as part of its - startup validation of configuration attributes. The - supports(Class) method is called by a security - interceptor implementation to ensure the configured - RunAsManager supports the type of secure object - that the security interceptor will present. - - One concrete implementation of a RunAsManager - is provided with Acegi Security. The - RunAsManagerImpl class returns a replacement - RunAsUserToken if any - ConfigAttribute starts with - RUN_AS_. If any such - ConfigAttribute is found, the replacement - RunAsUserToken will contain the same principal, - credentials and granted authorities as the original - Authentication object, along with a new - GrantedAuthorityImpl for each - RUN_AS_ ConfigAttribute. Each - new GrantedAuthorityImpl will be prefixed with - ROLE_, followed by the RUN_AS - ConfigAttribute. For example, a - RUN_AS_SERVER will result in the replacement - RunAsUserToken containing a - ROLE_RUN_AS_SERVER granted authority. - - The replacement RunAsUserToken is just like - any other Authentication object. It needs to be - authenticated by the AuthenticationManager, - probably via delegation to a suitable - AuthenticationProvider. The - RunAsImplAuthenticationProvider performs such - authentication. It simply accepts as valid any - RunAsUserToken presented. - - To ensure malicious code does not create a - RunAsUserToken and present it for guaranteed - acceptance by the RunAsImplAuthenticationProvider, - the hash of a key is stored in all generated tokens. The - RunAsManagerImpl and - RunAsImplAuthenticationProvider is created in the - bean context with the same key: - - -<bean id="runAsManager" class="org.acegisecurity.runas.RunAsManagerImpl"> - <property name="key"><value>my_run_as_password</value></property> -</bean> - -<bean id="runAsAuthenticationProvider" class="org.acegisecurity.runas.RunAsImplAuthenticationProvider"> - <property name="key"><value>my_run_as_password</value></property> -</bean> - - - - By using the same key, each RunAsUserToken - can be validated it was created by an approved - RunAsManagerImpl. The - RunAsUserToken is immutable after creation for - security reasons - - - - - Form Authentication Mechanism - - - Overview - - HTTP Form Authentication involves using the - AuthenticationProcessingFilter to process a login - form. This is the most common way that application authenticate end - users. Form-based authentication is entirely compatible with the DAO - and JAAS authentication providers. - - - - Configuration - - The login form simply contains j_username and - j_password input fields, and posts to a URL that is - monitored by the filter (by default - j_acegi_security_check). The filter is defined in - web.xml behind a - FilterToBeanProxy as follows: - - <filter> - <filter-name>Acegi Authentication Processing Filter</filter-name> - <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class> - <init-param> - <param-name>targetClass</param-name> - <param-value>org.acegisecurity.ui.webapp.AuthenticationProcessingFilter</param-value> - </init-param> -</filter> - -<filter-mapping> - <filter-name>Acegi Authentication Processing Filter</filter-name> - <url-pattern>/*</url-pattern> -</filter-mapping> - - For a discussion of FilterToBeanProxy, please - refer to the Filters section. The application context will need to - define the AuthenticationProcessingFilter: - - <bean id="authenticationProcessingFilter" class="org.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> - - The configured AuthenticationManager - processes each authentication request. If authentication fails, the - browser will be redirected to the - authenticationFailureUrl. The - AuthenticationException will be placed into the - HttpSession attribute indicated by - AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY, - enabling a reason to be provided to the user on the error page. - - If authentication is successful, the resulting - Authentication object will be placed into the - SecurityContextHolder. - - Once the SecurityContextHolder has been - updated, the browser will need to be redirected to the target URL. The - target URL is usually indicated by the HttpSession - attribute specified by - AbstractProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY. - This attribute is automatically set by the - ExceptionTranslationFilter when an - AuthenticationException occurs, so that after login - is completed the user can return to what they were trying to access. - If for some reason the HttpSession does not - indicate the target URL, the browser will be redirected to the - defaultTargetUrl property. - - - - - BASIC Authentication Mechanism - - - Overview - - Acegi Security provides a - BasicProcessingFilter which is capable of - processing basic authentication credentials presented in HTTP headers. - This can be used for authenticating calls made by Spring remoting - protocols (such as Hessian and Burlap), as well as normal user agents - (such as Internet Explorer and Navigator). The standard governing HTTP - Basic Authentication is defined by RFC 1945, Section 11, and the - BasicProcessingFilter conforms with this RFC. Basic - Authentication is an attractive approach to authentication, because it - is very widely deployed in user agents and implementation is extremely - simple (it's just a Base64 encoding of the username:password, - specified in an HTTP header). - - - - Configuration - - To implement HTTP Basic Authentication, it is necessary to - define BasicProcessingFilter in the filter chain. - The application context will need to define the - BasicProcessingFilter and its required - collaborator: - - -<bean id="basicProcessingFilter" class="org.acegisecurity.ui.basicauth.BasicProcessingFilter"> - <property name="authenticationManager"><ref bean="authenticationManager"/></property> - <property name="authenticationEntryPoint"><ref bean="authenticationEntryPoint"/></property> -</bean> - -<bean id="authenticationEntryPoint" class="org.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint"> - <property name="realmName"><value>Name Of Your Realm</value></property> -</bean> - - - - The configured AuthenticationManager - processes each authentication request. If authentication fails, the - configured AuthenticationEntryPoint will be used to - retry the authentication process. Usually you will use the - BasicProcessingFilterEntryPoint, which returns a - 401 response with a suitable header to retry HTTP Basic - authentication. If authentication is successful, the resulting - Authentication object will be placed into the - SecurityContextHolder. - - If the authentication event was successful, or authentication - was not attempted because the HTTP header did not contain a supported - authentication request, the filter chain will continue as normal. The - only time the filter chain will be interrupted is if authentication - fails and the AuthenticationEntryPoint is called, - as discussed in the previous paragraph - - - - - Digest Authentication - - - Overview - - Acegi Security provides a - DigestProcessingFilter which is capable of - processing digest authentication credentials presented in HTTP - headers. Digest Authentication attempts to solve many of the - weaknesses of Basic authentication, specifically by ensuring - credentials are never sent in clear text across the wire. Many user - agents support Digest Authentication, including FireFox and Internet - Explorer. The standard governing HTTP Digest Authentication is defined - by RFC 2617, which updates an earlier version of the Digest - Authentication standard prescribed by RFC 2069. Most user agents - implement RFC 2617. Acegi Security - DigestProcessingFilter is compatible with the - "auth" quality of protection - (qop) prescribed by RFC 2617, which also provides - backward compatibility with RFC 2069. Digest Authentication is a - highly attractive option if you need to use unencrypted HTTP (ie no - TLS/HTTPS) and wish to maximise security of the authentication - process. Indeed Digest Authentication is a mandatory requirement for - the WebDAV protocol, as noted by RFC 2518 Section 17.1, so we should - expect to see it increasingly deployed and replacing Basic - Authentication. - - Digest Authentication is definitely the most secure choice - between Form Authentication, Basic Authentication and Digest - Authentication, although extra security also means more complex user - agent implementations. Central to Digest Authentication is a "nonce". - This is a value the server generates. Acegi Security's nonce adopts - the following format: - - base64(expirationTime + ":" + md5Hex(expirationTime + ":" + key)) - -expirationTime: The date and time when the nonce expires, expressed in milliseconds -key: A private key to prevent modification of the nonce token - - - The DigestProcessingFilterEntryPoint has a - property specifying the key used for generating the - nonce tokens, along with a nonceValiditySeconds - property for determining the expiration time (default 300, which - equals five minutes). Whist ever the nonce is valid, the digest is - computed by concatenating various strings including the username, - password, nonce, URI being requested, a client-generated nonce (merely - a random value which the user agent generates each request), the realm - name etc, then performing an MD5 hash. Both the server and user agent - perform this digest computation, resulting in different hash codes if - they disagree on an included value (eg password). In Acegi Security - implementation, if the server-generated nonce has merely expired (but - the digest was otherwise valid), the - DigestProcessingFilterEntryPoint will send a - "stale=true" header. This tells the user agent - there is no need to disturb the user (as the password and username etc - is correct), but simply to try again using a new nonce. - - An appropriate value for - DigestProcessingFilterEntryPoint's - nonceValiditySeconds parameter will depend on your - application. Extremely secure applications should note that an - intercepted authentication header can be used to impersonate the - principal until the expirationTime contained in the - nonce is reached. This is the key principle when selecting an - appropriate setting, but it would be unusual for immensely secure - applications to not be running over TLS/HTTPS in the first - instance. - - Because of the more complex implementation of Digest - Authentication, there are often user agent issues. For example, - Internet Explorer fails to present an "opaque" - token on subsequent requests in the same session. Acegi Security - filters therefore encapsulate all state information into the - "nonce" token instead. In our testing, Acegi - Security implementation works reliably with FireFox and Internet - Explorer, correctly handling nonce timeouts etc. - - - - Configuration - - Now that we've reviewed the theory, let's see how to use it. To - implement HTTP Digest Authentication, it is necessary to define - DigestProcessingFilter in the fitler chain. The - application context will need to define the - DigestProcessingFilter and its required - collaborators: - - -<bean id="digestProcessingFilter" class="org.acegisecurity.ui.digestauth.DigestProcessingFilter"> - <property name="userDetailsService"><ref local="jdbcDaoImpl"/></property> - <property name="authenticationEntryPoint"><ref local="digestProcessingFilterEntryPoint"/></property> - <property name="userCache"><ref local="userCache"/></property> -</bean> - -<bean id="digestProcessingFilterEntryPoint" class="org.acegisecurity.ui.digestauth.DigestProcessingFilterEntryPoint"> - <property name="realmName"><value>Contacts Realm via Digest Authentication</value></property> - <property name="key"><value>acegi</value></property> - <property name="nonceValiditySeconds"><value>10</value></property> -</bean> - - - - The configured UserDetailsService is needed - because DigestProcessingFilter must have direct - access to the clear text password of a user. Digest Authentication - will NOT work if you are using encoded passwords in your DAO. The DAO - collaborator, along with the UserCache, are - typically shared directly with a - DaoAuthenticationProvider. The - authenticationEntryPoint property must be - DigestProcessingFilterEntryPoint, so that - DigestProcessingFilter can obtain the correct - realmName and key for digest - calculations. - - Like BasicAuthenticationFilter, if - authentication is successful an Authentication - request token will be placed into the - SecurityContextHolder. If the authentication event - was successful, or authentication was not attempted because the HTTP - header did not contain a Digest Authentication request, the filter - chain will continue as normal. The only time the filter chain will be - interrupted is if authentication fails and the - AuthenticationEntryPoint is called, as discussed in - the previous paragraph. - - Digest Authentication's RFC offers a range of additional - features to further increase security. For example, the nonce can be - changed on every request. Despite this, Acegi Security implementation - was designed to minimise the complexity of the implementation (and the - doubtless user agent incompatibilities that would emerge), and avoid - needing to store server-side state. You are invited to review RFC 2617 - if you wish to explore these features in more detail. As far as we are - aware, Acegi Security implementation does comply with the minimum - standards of this RFC. - - - - - Anonymous Authentication - - - Overview - - Particularly in the case of web request URI security, sometimes - it is more convenient to assign configuration attributes against every - possible secure object invocation. Put differently, sometimes it is - nice to say ROLE_SOMETHING is required by default - and only allow certain exceptions to this rule, such as for login, - logout and home pages of an application. There are also other - situations where anonymous authentication would be desired, such as - when an auditing interceptor queries the - SecurityContextHolder to identify which principal - was responsible for a given operation. Such classes can be authored - with more robustness if they know the - SecurityContextHolder always contains an - Authentication object, and never - null. - - - - Configuration - - Acegi Security provides three classes that together provide an - anonymous authentication feature. - AnonymousAuthenticationToken is an implementation - of Authentication, and stores the - GrantedAuthority[]s which apply to the anonymous - principal. There is a corresponding - AnonymousAuthenticationProvider, which is chained - into the ProviderManager so that - AnonymousAuthenticationTokens are accepted. - Finally, there is an AnonymousProcessingFilter, which is chained after - the normal authentication mechanisms and automatically add an - AnonymousAuthenticationToken to the - SecurityContextHolder if there is no existing - Authentication held there. The definition of the - filter and authentication provider appears as follows: - - -<bean id="anonymousProcessingFilter" class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter"> - <property name="key"><value>foobar</value></property> - <property name="userAttribute"><value>anonymousUser,ROLE_ANONYMOUS</value></property> -</bean> - -<bean id="anonymousAuthenticationProvider" class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider"> - <property name="key"><value>foobar</value></property> -</bean> - - - - The key is shared between the filter and - authentication provider, so that tokens created by the former are - accepted by the latter. The userAttribute is - expressed in the form of - usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]. - This is the same syntax as used after the equals sign for - InMemoryDaoImpl's userMap - property. - - As explained earlier, the benefit of anonymous authentication is - that all URI patterns can have security applied to them. For - example: - - -<bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor"> - <property name="authenticationManager"><ref bean="authenticationManager"/></property> - <property name="accessDecisionManager"><ref local="httpRequestAccessDecisionManager"/></property> - <property name="objectDefinitionSource"> - <value> - CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON - PATTERN_TYPE_APACHE_ANT - /index.jsp=ROLE_ANONYMOUS,ROLE_USER - /hello.htm=ROLE_ANONYMOUS,ROLE_USER - /logoff.jsp=ROLE_ANONYMOUS,ROLE_USER - /acegilogin.jsp*=ROLE_ANONYMOUS,ROLE_USER - /**=ROLE_USER - </value> - </property> -</bean> - - Rounding out the anonymous authentication discussion - is the AuthenticationTrustResolver interface, with - its corresponding AuthenticationTrustResolverImpl - implementation. This interface provides an - isAnonymous(Authentication) method, which allows - interested classes to take into account this special type of - authentication status. The - ExceptionTranslationFilter uses this interface in - processing AccessDeniedExceptions. If an - AccessDeniedException is thrown, and the - authentication is of an anonymous type, instead of throwing a 403 - (forbidden) response, the filter will instead commence the - AuthenticationEntryPoint so the principal can - authenticate properly. This is a necessary distinction, otherwise - principals would always be deemed "authenticated" and never be given - an opportunity to login via form, basic, digest or some other normal - authentication mechanism - - - - - Remember-Me Authentication - - - Overview - - Remember-me authentication refers to web sites being able to - remember the identity of a principal between sessions. This is - typically accomplished by sending a cookie to the browser, with the - cookie being detected during future sessions and causing automated - login to take place. Acegi Security provides the necessary hooks so - that such operations can take place, along with providing a concrete - implementation that uses hashing to preserve the security of - cookie-based tokens. - - - - Configuration - - Remember-me authentication is not used with basic - authentication, given it is often not used with - HttpSessions. Remember-me is used with - AuthenticationProcessingFilter, and is implemented - via hooks in the AbstractProcessingFilter - superclass. The hooks will invoke a concrete - RememberMeServices at the appropriate times. The - interface looks like this: - - public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response); -public void loginFail(HttpServletRequest request, HttpServletResponse response); -public void loginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication); - - Please refer to JavaDocs for a fuller discussion on what the - methods do, although note at this stage - AbstractProcessingFilter only calls the - loginFail() and loginSuccess() - methods. The autoLogin() method is called by - RememberMeProcessingFilter whenever the - SecurityContextHolder does not contain an - Authentication. This interface therefore provides - the underlaying remember-me implementation with sufficient - notification of authentication-related events, and delegates to the - implementation whenever a candidate web request might contain a cookie - and wish to be remembered. - - This design allows any number of remember-me implementation - strategies. In the interests of simplicity and avoiding the need for - DAO implementations that specify write and create methods, Acegi - Security's only concrete implementation, - TokenBasedRememberMeServices, uses hashing to - achieve a useful remember-me strategy. In essence a cookie is sent to - the browser upon successful interactive authentication, with that - cookie being composed as follows: - - base64(username + ":" + expirationTime + ":" + md5Hex(username + ":" + expirationTime + ":" password + ":" + key)) - -username: As identifiable to TokenBasedRememberMeServices.getUserDetailsService() -password: That matches the relevant UserDetails retrieved from TokenBasedRememberMeServices.getUserDetailsService() -expirationTime: The date and time when the remember-me token expires, expressed in milliseconds -key: A private key to prevent modification of the remember-me token - - - As such the remember-me token is valid only for the period - specified, and provided that the username, password and key does not - change. Notably, this has a potential security issue in that a - captured remember-me token will be usable from any user agent until - such time as the token expires. This is the same issue as with digest - authentication. If a principal is aware a token has been captured, - they can easily change their password and immediately invalidate all - remember-me tokens on issue. However, if more significant security is - needed a rolling token approach should be used (this would require a - database) or remember-me services should simply not be used. - - TokenBasedRememberMeServices generates a - RememberMeAuthenticationToken, which is processed - by RememberMeAuthenticationProvider. A - key is shared between this authentication provider - and the TokenBasedRememberMeServices. In addition, - TokenBasedRememberMeServices requires A - UserDetailsService from which it can retrieve the username and - password for signature comparison purposes, and generate the - RememberMeAuthenticationToken to contain the - correct GrantedAuthority[]s. Some sort of logout - command should be provided by the application (typically via a JSP) - that invalidates the cookie upon user request. See the Contacts Sample - application's logout.jsp for an example. - - The beans required in an application context to enable - remember-me services are as follows: - - -<bean id="rememberMeProcessingFilter" class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter"> - <property name="rememberMeServices"><ref local="rememberMeServices"/></property> -</bean> - -<bean id="rememberMeServices" class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices"> - <property name="userDetailsService"><ref local="jdbcDaoImpl"/></property> - <property name="key"><value>springRocks</value></property> -</bean> - -<bean id="rememberMeAuthenticationProvider" class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider"> - <property name="key"><value>springRocks</value></property> -</bean> - - Don't forget to add your - RememberMeServices implementation to your - AuthenticationProcessingFilter.setRememberMeServices() - property, include the - RememberMeAuthenticationProvider in your - AuthenticationManager.setProviders() list, and add - a call to RememberMeProcessingFilter into your - FilterChainProxy (typically immediately after your - AuthenticationProcessingFilter) - - - - - X509 Authentication - - - Overview - - The most common use of X509 certificate authentication is in - verifying the identity of a server when using SSL, most commonly when - using HTTPS from a browser. The browser will automatically check that - the certificate presented by a server has been issued (ie digitally - signed) by one of a list of trusted certificate authorities which it - maintains. - - You can also use SSL with mutual authentication; - the server will then request a valid certificate from the client as - part of the SSL handshake. The server will authenticate the client by - checking that it's certificate is signed by an acceptable authority. - If a valid certificate has been provided, it can be obtained through - the servlet API in an application. Acegi Security X509 module extracts - the certificate using a filter and passes it to the configured X509 - authentication provider to allow any additional application-specific - checks to be applied. It also maps the certificate to an application - user and loads that user's set of granted authorities for use with the - standard Acegi Security infrastructure. - - You should be familiar with using certificates and setting up - client authentication for your servlet container before attempting to - use it with Acegi Security. Most of the work is in creating and - installing suitable certificates and keys. For example, if you're - using Tomcat then read the instructions here . - It's important that you get this working before trying it out with - Acegi Security - - - - Using X509 with Acegi Security - - With X509 authentication, there is no explicit login procedure - so the implementation is relatively simple; there is no need to - redirect requests in order to interact with the user. As a result, - some of the classes behave slightly differently from their equivalents - in other packages. For example, the default entry point - class, which is normally responsible for starting the authentication - process, is only invoked if the certificate is rejected and it always - returns an error to the user. With a suitable bean configuration, the - normal sequence of events is as follows - - The X509ProcessingFilter extracts - the certificate from the request and uses it as the credentials - for an authentication request. The generated authentication - request is an X509AuthenticationToken. - The request is passed to the authentication manager. - - - - The X509AuthenticationProvider - receives the token. Its main concern is to obtain the user - information (in particular the user's granted authorities) that - matches the certificate. It delegates this responsibility to an - X509AuthoritiesPopulator. - - - - The populator's single method, - getUserDetails(X509Certificate - userCertificate) is invoked. Implementations should - return a UserDetails instance containing - the array of GrantedAuthority objects for - the user. This method can also choose to reject the certificate - (for example if it doesn't contain a matching user name). In - such cases it should throw a - BadCredentialsException. A - DAO-based implementation, - DaoX509AuthoritiesPopulator, is provided - which extracts the user's name from the subject common - name (CN) in the certificate. It also allows you to set - your own regular expression to match a different part of the - subject's distinguished name. A UserDetailsService is used to - load the user information. - - - - If everything has gone smoothly then there should be a - valid Authentication object in the secure - context and the invocation will procede as normal. If no - certificate was found, or the certificate was rejected, then the - ExceptionTranslationFilter will invoke - the X509ProcessingFilterEntryPoint which - returns a 403 error (forbidden) to the user. - - - - - - Configuration - - There is a version of the Contacts Sample Application which - uses X509. Copy the beans and filter setup from this as a starting - point for configuring your own application. A set of example - certificates is also included which you can use to configure your - server. These are - - marissa.p12: A PKCS12 format file - containing the client key and certificate. These should be - installed in your browser. It maps to the user - marissa in the application. - - - - server.p12: The server certificate - and key for HTTPS connections. - - - - ca.jks: A Java keystore containing - the certificate for the authority which issued marissa's - certificate. This will be used by the container to validate - client certificates. - - For JBoss 3.2.7 (with Tomcat 5.0), the SSL - configuration in the server.xml file looks like - this -<!-- SSL/TLS Connector configuration --> -<Connector port="8443" address="${jboss.bind.address}" - maxThreads="100" minSpareThreads="5" maxSpareThreads="15" - scheme="https" secure="true" - sslProtocol = "TLS" - clientAuth="true" keystoreFile="${jboss.server.home.dir}/conf/server.p12" - keystoreType="PKCS12" keystorePass="password" - truststoreFile="${jboss.server.home.dir}/conf/ca.jks" - truststoreType="JKS" truststorePass="password" -/> - - clientAuth can also be set to - want if you still want SSL connections to - succeed even if the client doesn't provide a certificate. Obviously - these clients won't be able to access any objects secured by Acegi - Security (unless you use a non-X509 authentication mechanism, such as - BASIC authentication, to authenticate the user) - - - - - LDAP Authentication - - - Overview - - LDAP is often used by organizations as a central repository for - user information and as an authentication service. It can also be used - to store the role information for application users. - - There are many different scenarios for how an LDAP server may be - configured so Acegi LDAP provider is fully configurable. It uses - separate strategy interfaces for authentication and role retrieval and - provides default implementations which can be configured to handle a - wide range of situations. - - You should be familiar with LDAP before trying to use it with - Acegi. The following link provides a good introduction to the concepts - involved and a guide to setting up a directory using the free LDAP - server OpenLDAP: . Some familiarity - with the JNDI APIs used to access LDAP from Java may also be useful. - We don't use any third-party LDAP libraries (Mozilla/Netscape, JLDAP - etc.) in the LDAP provider. - - - - Using LDAP with Acegi Security - - The main LDAP provider class is - org.acegisecurity.providers.ldap.LdapAuthenticationProvider. - This bean doesn't actually do much itself other than implement the - retrieveUser method required by its base - class, - AbstractUserDetailsAuthenticationProvider. It - delegates the work to two other beans, an - LdapAuthenticator and an - LdapAuthoritiesPopulator which are - responsible for authenticating the user and retrieving the user's set - of GrantedAuthoritys - respectively. - - - LdapAuthenticator Implementations - - The authenticator is also responsible for retrieving any - required user attributes. This is because the permissions on the - attributes may depend on the type of authentication being used. For - example, if binding as the user, it may be necessary to read them - with the user's own permissions. - - There are currently two authentication strategies supplied - with Acegi Security: - - Authentication directly to the LDAP server ("bind" - authentication). - - - - Password comparison, where the password supplied by the - user is compared with the one stored in the repository. This - can either be done by retrieving the value of the password - attribute and checking it locally or by performing an LDAP - "compare" operation, where the supplied password is passed to - the server for comparison and the real password value is never - retrieved. - - - - - Common Functionality - - Before it is possible to authenticate a user (by either - strategy), the distinguished name (DN) has to be obtained from the - login name supplied to the application. This can be done either by - simple pattern-matching (by setting the - setUserDnPatterns array property) or by - setting the userSearch property. For the DN - pattern-matching approach, a standard Java pattern format is used, - and the login name will be substituted for the parameter - {0}. The pattern should be relative to the - DN that the configured - InitialDirContextFactory will bind - to (see the section on connecting to the LDAP - server for more information on this). For example, if you - are using an LDAP server specified by the URL - ldap://monkeymachine.co.uk/dc=acegisecurity,dc=org, - and have a pattern uid={0},ou=greatapes, then a - login name of "gorilla" will map to a DN - uid=gorilla,ou=greatapes,dc=acegisecurity,dc=org. - Each configured DN pattern will be tried in turn until a match is - found. For information on using a search, see the section on search objects below. A - combination of the two approaches can also be used - the patterns - will be checked first and if no matching DN is found, the search - will be used. - - - - BindAuthenticator - - The class - org.acegisecurity.providers.ldap.authenticator.BindAuthenticator - implements the bind authentication strategy. It simply attempts to - bind as the user. - - - - PasswordComparisonAuthenticator - - The class - org.acegisecurity.providers.ldap.authenticator.PasswordComparisonAuthenticator - implements the password comparison authentication strategy. - - - - Active Directory Authentication - - In addition to standard LDAP authentication (binding with a - DN), Active Directory has its own non-standard syntax for user - authentication. - - - - - Connecting to the LDAP Server - - The beans discussed above have to be able to connect to the - server. They both have to be supplied with an - InitialDirContextFactory instance. - Unless you have special requirements, this will usually be a - DefaultInitialDirContextFactory bean, which - can be configured with the URL of your LDAP server and optionally - with the username and password of a "manager" user which will be - used by default when binding to the server (instead of binding - anonymously). It currently supports "simple" LDAP - authentication. - - DefaultInitialDirContextFactory uses - Sun's JNDI LDAP implementation by default (the one that comes with - the JDK). It also supports the built in connection pooling offered - by Sun's provider. Connections which are obtained either anonymously - or with the "manager" user's identity will be pooled automatically. - Connections obtained with a specific user's identity will not be - pooled. Connection pooling can be disabled completely by setting the - useConnectionPool property to false. - - See the class - Javadoc and source for more information on this bean and its - properties. - - - - LDAP Search Objects - - Often more a more complicated strategy than simple DN-matching - is required to locate a user entry in the directory. This can be - encapsulated in an LdapUserSearch - instance which can be supplied to the authenticator implementations, - for example, to allow them to locate a user. The supplied - implementation is - FilterBasedLdapUserSearch. - - - <classname>FilterBasedLdapUserSearch</classname> - - This bean uses an LDAP filter to match the user object in - the directory. The process is explained in the Javadoc for the - corresponding search method on the JDK - DirContext class. As explained there, the search filter - can be supplied with parameters. For this class, the only valid - parameter is {0} which will be replaced - with the user's login name. - - - - - - Configuration - - There is a version of the Contacts Sample Application which - uses LDAP. You can copy the beans and filter setup from this as a - starting point for configuring your own application. - - A typical configuration, using some of the beans we've discussed - above, might look like this: - <bean id="initialDirContextFactory" - class="org.acegisecurity.ldap.DefaultInitialDirContextFactory"> - <constructor-arg value="ldap://monkeymachine:389/dc=acegisecurity,dc=org"/> - <property name="managerDn"><value>cn=manager,dc=acegisecurity,dc=org</value></property> - <property name="managerPassword"><value>password</value></property> - </bean> - - <bean id="userSearch" - class="org.acegisecurity.ldap.search.FilterBasedLdapUserSearch"> - <constructor-arg index="0"> - <value></value> - </constructor-arg> - <constructor-arg index="1"> - <value>(uid={0})</value> - </constructor-arg> - <constructor-arg index="2"> - <ref local="initialDirContextFactory" /> - </constructor-arg> - <property name="searchSubtree"> - <value>true</value> - </property> - </bean> - - <bean id="ldapAuthProvider" - class="org.acegisecurity.providers.ldap.LdapAuthenticationProvider"> - <constructor-arg> - <bean class="org.acegisecurity.providers.ldap.authenticator.BindAuthenticator"> - <constructor-arg><ref local="initialDirContextFactory"/></constructor-arg> - <property name="userDnPatterns"><list><value>uid={0},ou=people</value></list></property> - </bean> - </constructor-arg> - <constructor-arg> - <bean class="org.acegisecurity.providers.ldap.populator.DefaultLdapAuthoritiesPopulator"> - <constructor-arg><ref local="initialDirContextFactory"/></constructor-arg> - <constructor-arg><value>ou=groups</value></constructor-arg> - <property name="groupRoleAttribute"><value>ou</value></property> - </bean> - </constructor-arg> - </bean> - - This would set up the provider to access an LDAP - server with URL - ldap://monkeymachine:389/dc=acegisecurity,dc=org. - Authentication will be performed by attempting to bind with the DN - uid=<user-login-name>,ou=people,dc=acegisecurity,dc=org. - After successful authentication, roles will be assigned to the user by - searching under the DN - ou=groups,dc=acegisecurity,dc=org with the default - filter (member=<user's-DN>). The role name - will be taken from the ou attribute of each - match. - - We've also included the configuration for a user search object, - which uses the filter - (uid=<user-login-name>). This could be used - instead of the DN-pattern (or in addition to it), by setting the - authenticator's userSearch property. The - authenticator would then call the search object to obtain the correct - user's DN before attempting to bind as this user. - - - - - CAS Authentication - - - Overview - - JA-SIG produces an enterprise-wide single sign on system known - as CAS. Unlike other initiatives, JA-SIG's Central Authentication - Service is open source, widely used, simple to understand, platform - independent, and supports proxy capabilities. Acegi Security fully - supports CAS, and provides an easy migration path from - single-application deployments of Acegi Security through to - multiple-application deployments secured by an enterprise-wide CAS - server. - - You can learn more about CAS at - http://www.ja-sig.org/products/cas/. You will need - to visit this URL to download the CAS Server files. Whilst Acegi - Security includes two CAS libraries in the "-with-dependencies" ZIP - file, you will still need the CAS Java Server Pages and - web.xml to customise and deploy your CAS - server. - - - - How CAS Works - - Whilst the CAS web site above contains two documents that detail - the architecture of CAS, we present the general overview again here - within the context of Acegi Security. The following refers to both CAS - 2.0 (produced by Yale) and CAS 3.0 (produced by JA-SIG), being the - versions of CAS that Acegi Security supports. - - Somewhere in your enterprise you will need to setup a CAS - server. The CAS server is simply a standard WAR file, so there isn't - anything difficult about setting up your server. Inside the WAR file - you will customise the login and other single sign on pages displayed - to users. - - If you are deploying CAS 2.0, you will also need to specify in - the web.xml a PasswordHandler. The - PasswordHandler has a simple method that returns a - boolean as to whether a given username and password is valid. Your - PasswordHandler implementation will need to link - into some type of backend authentication repository, such as an LDAP - server or database. - - If you are already running an existing CAS 2.0 server instance, - you will have already established a - PasswordHandler. If you do not already have a - PasswordHandler, you might prefer to use Acegi - Security CasPasswordHandler class. This class - delegates through to the standard Acegi Security - AuthenticationManager, enabling you to use a - security configuration you might already have in place. You do not - need to use the CasPasswordHandler class on your - CAS server if you do not wish. Acegi Security will function as a CAS - client successfully irrespective of the - PasswordHandler you've chosen for your CAS - server. - - If you are deploying CAS 3.0, you will also need to specify an - AuthenticationHandler in the - deployerConfigContext.xml included with CAS. The - AuthenticationHandler has a simple method that - returns a boolean as to whether a given set of Credentials is valid. - Your AuthenticationHandler implementation will need - to link into some type of backend authentication repository, such as - an LDAP server or database. CAS itself includes numerous - AuthenticationHandlers out of the box to assist - with this. - - If you are already running an existing CAS 3.0 server instance, - you will have already established an - AuthenticationHandler. If you do not already have - an AuthenticationHandler, you might prefer to use - Acegi Security CasAuthenticationHandler class. This - class delegates through to the standard Acegi Security - AuthenticationManager, enabling you to use a - security configuration you might already have in place. You do not - need to use the CasAuthenticationHandler class on - your CAS server if you do not wish. Acegi Security will function as a - CAS client successfully irrespective of the - AuthenticationHandler you've chosen for your CAS - server. - - Apart from the CAS server itself, the other key player is of - course the secure web applications deployed throughout your - enterprise. These web applications are known as "services". There are - two types of services: standard services and proxy services. A proxy - service is able to request resources from other services on behalf of - the user. This will be explained more fully later. - - Services can be developed in a large variety of languages, due - to CAS 2.0's very light XML-based protocol. The JA-SIG CAS home page - contains a clients archive which demonstrates CAS clients in Java, - Active Server Pages, Perl, Python and others. Naturally, Java support - is very strong given the CAS server is written in Java. You do not - need to use any of CAS' client classes in applications secured by - Acegi Security. This is handled transparently for you. - - The basic interaction between a web browser, CAS server and an - Acegi Security for System Spring secured service is as follows: - - - - The web user is browsing the service's public pages. CAS or - Acegi Security is not involved. - - - - The user eventually requests a page that is either secure or - one of the beans it uses is secure. Acegi Security's - ExceptionTranslationFilter will detect the - AuthenticationException. - - - - Because the user's Authentication object - (or lack thereof) caused an - AuthenticationException, the - ExceptionTranslationFilter will call the - configured AuthenticationEntryPoint. If using - CAS, this will be the - CasProcessingFilterEntryPoint class. - - - - The CasProcessingFilterEntry point will - redirect the user's browser to the CAS server. It will also - indicate a service parameter, which is the - callback URL for Acegi Security service. For example, the URL to - which the browser is redirected might be - https://my.company.com/cas/login?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Fj_acegi_cas_security_check. - - - - After the user's browser redirects to CAS, they will be - prompted for their username and password. If the user presents a - session cookie which indicates they've previously logged on, they - will not be prompted to login again (there is an exception to this - procedure, which we'll cover later). CAS will use the - PasswordHandler (or - AuthenticationHandler if using CAS 3.0) - discussed above to decide whether the username and password is - valid. - - - - Upon successful login, CAS will redirect the user's browser - back to the original service. It will also include a - ticket parameter, which is an opaque string - representing the "service ticket". Continuing our earlier example, - the URL the browser is redirected to might be - https://server3.company.com/webapp/j_acegi_cas_security_check?ticket=ST-0-ER94xMJmn6pha35CQRoZ. - - - - Back in the service web application, the - CasProcessingFilter is always listening for - requests to /j_acegi_cas_security_check (this - is configurable, but we'll use the defaults in this introduction). - The processing filter will construct a - UsernamePasswordAuthenticationToken - representing the service ticket. The principal will be equal to - CasProcessingFilter.CAS_STATEFUL_IDENTIFIER, - whilst the credentials will be the service ticket opaque value. - This authentication request will then be handed to the configured - AuthenticationManager. - - - - The AuthenticationManager implementation - will be the ProviderManager, which is in turn - configured with the CasAuthenticationProvider. - The CasAuthenticationProvider only responds to - UsernamePasswordAuthenticationTokens containing - the CAS-specific principal (such as - CasProcessingFilter.CAS_STATEFUL_IDENTIFIER) - and CasAuthenticationTokens (discussed - later). - - - - CasAuthenticationProvider will validate - the service ticket using a TicketValidator - implementation. Acegi Security includes one implementation, the - CasProxyTicketValidator. This implementation a - ticket validation class included in the CAS client library. The - CasProxyTicketValidator makes an HTTPS request - to the CAS server in order to validate the service ticket. The - CasProxyTicketValidator may also include a - proxy callback URL, which is included in this example: - https://my.company.com/cas/proxyValidate?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Fj_acegi_cas_security_check&ticket=ST-0-ER94xMJmn6pha35CQRoZ&pgtUrl=https://server3.company.com/webapp/casProxy/receptor. - - - - Back on the CAS server, the proxy validation request will be - received. If the presented service ticket matches the service URL - the ticket was issued to, CAS will provide an affirmative response - in XML indicating the username. If any proxy was involved in the - authentication (discussed below), the list of proxies is also - included in the XML response. - - - - [OPTIONAL] If the request to the CAS validation service - included the proxy callback URL (in the pgtUrl - parameter), CAS will include a pgtIou string in - the XML response. This pgtIou represents a - proxy-granting ticket IOU. The CAS server will then create its own - HTTPS connection back to the pgtUrl. This is to - mutually authenticate the CAS server and the claimed service URL. - The HTTPS connection will be used to send a proxy granting ticket - to the original web application. For example, - https://server3.company.com/webapp/casProxy/receptor?pgtIou=PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt&pgtId=PGT-1-si9YkkHLrtACBo64rmsi3v2nf7cpCResXg5MpESZFArbaZiOKH. - We suggest you use CAS' ProxyTicketReceptor - servlet to receive these proxy-granting tickets, if they are - required. - - - - The CasProxyTicketValidator will parse - the XML received from the CAS server. It will return to the - CasAuthenticationProvider a - TicketResponse, which includes the username - (mandatory), proxy list (if any were involved), and proxy-granting - ticket IOU (if the proxy callback was requested). - - - - Next CasAuthenticationProvider will call - a configured CasProxyDecider. The - CasProxyDecider indicates whether the proxy - list in the TicketResponse is acceptable to the - service. Several implementations are provided with Acegi Security - System: RejectProxyTickets, - AcceptAnyCasProxy and - NamedCasProxyDecider. These names are largely - self-explanatory, except NamedCasProxyDecider - which allows a List of trusted proxies to be - provided. - - - - CasAuthenticationProvider will next - request a CasAuthoritiesPopulator to advise the - GrantedAuthority objects that apply to the user - contained in the TicketResponse. Acegi Security - includes a DaoCasAuthoritiesPopulator which - simply uses the UserDetailsService - infrastructure to find the UserDetails and - their associated GrantedAuthoritys. Note that - the password and enabled/disabled status of - UserDetails returned by the - UserDetailsService are ignored, as the CAS - server is responsible for authentication decisions. - DaoCasAuthoritiesPopulator is only concerned - with retrieving the GrantedAuthoritys. - - - - If there were no problems, - CasAuthenticationProvider constructs a - CasAuthenticationToken including the details - contained in the TicketResponse and the - GrantedAuthoritys. The - CasAuthenticationToken contains the hash of a - key, so that the CasAuthenticationProvider - knows it created it. - - - - Control then returns to - CasProcessingFilter, which places the created - CasAuthenticationToken into the - HttpSession attribute named - HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY. - - - - The user's browser is redirected to the original page that - caused the AuthenticationException. - - - - As the Authentication object is now in - the well-known location, it is handled like any other - authentication approach. Usually the - HttpSessionIntegrationFilter will be used to - associate the Authentication object with the - SecurityContextHolder for the duration of each - request. - - - - It's good that you're still here! It might sound involved, but - you can relax as Acegi Security classes hide much of the complexity. - Let's now look at how this is configured - - - - Optional CAS Server Setup - - Acegi Security can even act as the backend which a CAS version - 2.0 or 3.0 server utilises. The configuration approach is described - below. Of course, if you have an existing CAS environment you might - just like to use it instead. - - - CAS Version 2.0 - - As mentioned above, Acegi Security includes a - PasswordHandler that bridges your existing - AuthenticationManager into CAS 2.0. You do not - need to use this PasswordHandler to use Acegi - Security on the client side (any CAS - PasswordHandler will do). - - To install, you will need to download and extract the CAS - server archive. We used version 2.0.12. There will be a - /web directory in the root of the deployment. - Copy an applicationContext.xml containing your - AuthenticationManager as well as the - CasPasswordHandler into the - /web/WEB-INF directory. A sample - applicationContext.xml is included below: - - -<bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl"> - <property name="userMap"> - <value> - marissa=koala,ROLES_IGNORED_BY_CAS - dianne=emu,ROLES_IGNORED_BY_CAS - scott=wombat,ROLES_IGNORED_BY_CAS - peter=opal,disabled,ROLES_IGNORED_BY_CAS - </value> - </property> -</bean> - -<bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"> - <property name="userDetailsService"><ref bean="inMemoryDaoImpl"/></property> -</bean> - -<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"> - <property name="providers"> - <list> - <ref bean="daoAuthenticationProvider"/> - </list> - </property> -</bean> - -<bean id="casPasswordHandler" class="org.acegisecurity.adapters.cas.CasPasswordHandler"> - <property name="authenticationManager"><ref bean="authenticationManager"/></property> -</bean> - - - - Note the granted authorities are ignored by CAS because it has - no way of communicating the granted authorities to calling - applications. CAS is only concerned with username and passwords (and - the enabled/disabled status). - - Next you will need to edit the existing - /web/WEB-INF/web.xml file. Add (or edit in the - case of the authHandler property) the following - lines: - - - -<context-param> - <param-name>edu.yale.its.tp.cas.authHandler</param-name> - <param-value>org.acegisecurity.adapters.cas.CasPasswordHandlerProxy</param-value> -</context-param> - -<context-param> - <param-name>contextConfigLocation</param-name> - <param-value>/WEB-INF/applicationContext.xml</param-value> -</context-param> - -<listener> - <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> -</listener> - - - - Copy the spring.jar and - acegi-security.jar files into - /web/WEB-INF/lib. Now use the ant - dist task in the build.xml in the root - of the directory structure. This will create - /lib/cas.war, which is ready for deployment to - your servlet container. - - Note CAS heavily relies on HTTPS. You can't even test the - system without an HTTPS certificate. Whilst you should refer to your - web container's documentation on setting up HTTPS, if you need some - additional help or a test certificate you might like to check the - samples/contacts/etc/ssl directory - - - - CAS Version 3.0 - - As mentioned above, Acegi Security includes an - AuthenticationHandler that bridges your existing - AuthenticationManager into CAS 3.0. You do not - need to use this AuthenticationHandler to use - Acegi Security on the client side (any CAS - AuthenticationHandler will do). - - To install, you will need to download and extract the CAS - server archive. We used version 3.0.4. There will be a - /webapp directory in the root of the deployment. - Edit the an deployerConfigContext.xml so that it - contains your AuthenticationManager as well as - the CasAuthenticationHandler. A sample - applicationContext.xml is included below: - - - <?xml version="1.0" encoding="UTF-8"?> - <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> - <beans> - <bean - id="authenticationManager" - class="org.jasig.cas.authentication.AuthenticationManagerImpl"> - <property name="credentialsToPrincipalResolvers"> - <list> - <bean class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver" /> - <bean class="org.jasig.cas.authentication.principal.HttpBasedServiceCredentialsToPrincipalResolver" /> - </list> - </property> - - <property name="authenticationHandlers"> - <list> - <bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler" /> - <bean class="org.acegisecurity.adapters.cas3.CasAuthenticationHandler"> - <property name="authenticationManager" ref="acegiAuthenticationManager" /> - </bean> - </list> - </property> - </bean> - - - <bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl"> - <property name="userMap"> - <value> - marissa=koala,ROLES_IGNORED_BY_CAS - dianne=emu,ROLES_IGNORED_BY_CAS - scott=wombat,ROLES_IGNORED_BY_CAS - peter=opal,disabled,ROLES_IGNORED_BY_CAS - </value> - </property> - </bean> - - <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"> - <property name="userDetailsService"><ref bean="inMemoryDaoImpl"/></property> - </bean> - - <bean id="acegiAuthenticationManager" class="org.acegisecurity.providers.ProviderManager"> - <property name="providers"> - <list> - <ref bean="daoAuthenticationProvider"/> - </list> - </property> - </bean> - </beans> - - - - Note the granted authorities are ignored by CAS because it has - no way of communicating the granted authorities to calling - applications. CAS is only concerned with username and passwords (and - the enabled/disabled status). - - Copy acegi-security.jar and - acegi-security-cas.jar files into - /localPlugins/lib. Now use the ant - war task in the build.xml in the - /localPlugins directory. This will create - /localPlugins/target/cas.war, which is ready for - deployment to your servlet container. - - Note CAS heavily relies on HTTPS. You can't even test the - system without an HTTPS certificate. Whilst you should refer to your - web container's documentation on setting up HTTPS, if you need some - additional help or a test certificate you might like to check the - CAS documentation on setting up SSL: - http://www.ja-sig.org/products/cas/server/ssl/index.html - - - - - Configuration of CAS Client - - The web application side of CAS is made easy due to Acegi - Security. It is assumed you already know the basics of using Acegi - Security, so these are not covered again below. Only the CAS-specific - beans are mentioned. - - You will need to add a ServiceProperties bean - to your application context. This represents your service: - - - -<bean id="serviceProperties" class="org.acegisecurity.ui.cas.ServiceProperties"> - <property name="service"><value>https://localhost:8443/contacts-cas/j_acegi_cas_security_check</value></property> - <property name="sendRenew"><value>false</value></property> -</bean> - - - - The service must equal a URL that will be - monitored by the CasProcessingFilter. The - sendRenew defaults to false, but should be set to - true if your application is particularly sensitive. What this - parameter does is tell the CAS login service that a single sign on - login is unacceptable. Instead, the user will need to re-enter their - username and password in order to gain access to the service. - - The following beans should be configured to commence the CAS - authentication process: - - -<bean id="casProcessingFilter" class="org.acegisecurity.ui.cas.CasProcessingFilter"> - <property name="authenticationManager"><ref bean="authenticationManager"/></property> - <property name="authenticationFailureUrl"><value>/casfailed.jsp</value></property> - <property name="defaultTargetUrl"><value>/</value></property> - <property name="filterProcessesUrl"><value>/j_acegi_cas_security_check</value></property> -</bean> - -<bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter"> - <property name="authenticationEntryPoint"><ref local="casProcessingFilterEntryPoint"/></property> -</bean> - -<bean id="casProcessingFilterEntryPoint" class="org.acegisecurity.ui.cas.CasProcessingFilterEntryPoint"> - <property name="loginUrl"><value>https://localhost:8443/cas/login</value></property> - <property name="serviceProperties"><ref bean="serviceProperties"/></property> -</bean> - - - - You will also need to add the - CasProcessingFilter to web.xml: - - -<filter> - <filter-name>Acegi CAS Processing Filter</filter-name> - <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class> - <init-param> - <param-name>targetClass</param-name> - <param-value>org.acegisecurity.ui.cas.CasProcessingFilter</param-value> - </init-param> -</filter> - -<filter-mapping> - <filter-name>Acegi CAS Processing Filter</filter-name> - <url-pattern>/*</url-pattern> -</filter-mapping> - - - - The CasProcessingFilter has very similar - properties to the AuthenticationProcessingFilter - (used for form-based logins). Each property is - self-explanatory. - - For CAS to operate, the - ExceptionTranslationFilter must have its - authenticationEntryPoint property set to the - CasProcessingFilterEntryPoint bean. - - The CasProcessingFilterEntryPoint must refer - to the ServiceProperties bean (discussed above), - which provides the URL to the enterprise's CAS login server. This is - where the user's browser will be redirected. - - Next you need to add an AuthenticationManager - that uses CasAuthenticationProvider and its - collaborators: - - -<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"> - <property name="providers"> - <list> - <ref bean="casAuthenticationProvider"/> - </list> - </property> -</bean> - -<bean id="casAuthenticationProvider" class="org.acegisecurity.providers.cas.CasAuthenticationProvider"> - <property name="casAuthoritiesPopulator"><ref bean="casAuthoritiesPopulator"/></property> - <property name="casProxyDecider"><ref bean="casProxyDecider"/></property> - <property name="ticketValidator"><ref bean="casProxyTicketValidator"/></property> - <property name="statelessTicketCache"><ref bean="statelessTicketCache"/></property> - <property name="key"><value>my_password_for_this_auth_provider_only</value></property> -</bean> - -<bean id="casProxyTicketValidator" class="org.acegisecurity.providers.cas.ticketvalidator.CasProxyTicketValidator"> - <property name="casValidate"><value>https://localhost:8443/cas/proxyValidate</value></property> - <property name="proxyCallbackUrl"><value>https://localhost:8443/contacts-cas/casProxy/receptor</value></property> - <property name="serviceProperties"><ref bean="serviceProperties"/></property> - <!-- <property name="trustStore"><value>/some/path/to/your/lib/security/cacerts</value></property> --> -</bean> - -<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> - <property name="configLocation"> - <value>classpath:/ehcache-failsafe.xml</value> - </property> -</bean> - -<bean id="ticketCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean"> - <property name="cacheManager"> - <ref local="cacheManager"/> - </property> - <property name="cacheName"> - <value>ticketCache</value> - </property> -</bean> - -<bean id="statelessTicketCache" class="org.acegisecurity.providers.cas.cache.EhCacheBasedTicketCache"> - <property name="cache"><ref local="ticketCacheBackend"/></property> -</bean> - -<bean id="casAuthoritiesPopulator" class="org.acegisecurity.providers.cas.populator.DaoCasAuthoritiesPopulator"> - <property name="userDetailsService"><ref bean="inMemoryDaoImpl"/></property> -</bean> - -<bean id="casProxyDecider" class="org.acegisecurity.providers.cas.proxy.RejectProxyTickets"/> - - - - The beans are all reasonable self-explanatory if you refer back - to the "How CAS Works" section. Careful readers might notice one - surprise: the statelessTicketCache property of the - CasAuthenticationProvider. This is discussed in - detail in the "Advanced CAS Usage" section. - - Note the CasProxyTicketValidator has a - remarked out trustStore property. This property - might be helpful if you experience HTTPS certificate issues. Also note - the proxyCallbackUrl is set so the service can - receive a proxy-granting ticket. As mentioned above, this is optional - and unnecessary if you do not require proxy-granting tickets. If you - do use this feature, you will need to configure a suitable servlet to - receive the proxy-granting tickets. We suggest you use CAS' - ProxyTicketReceptor by adding the following to your - web application's web.xml: - - -<servlet> - <servlet-name>casproxy</servlet-name> - <servlet-class>edu.yale.its.tp.cas.proxy.ProxyTicketReceptor</servlet-class> -</servlet> - -<servlet-mapping> - <servlet-name>casproxy</servlet-name> - <url-pattern>/casProxy/*</url-pattern> -</servlet-mapping> - - - - This completes the configuration of CAS. If you haven't made any - mistakes, your web application should happily work within the - framework of CAS single sign on. No other parts of Acegi Security need - to be concerned about the fact CAS handled authentication. - - There is also a contacts-cas.war file in the - sample applications directory. This sample application uses the above - settings and can be deployed to see CAS in operation - - - - Advanced Issues - - The CasAuthenticationProvider distinguishes - between stateful and stateless clients. A stateful client is - considered any that originates via the - CasProcessingFilter. A stateless client is any that - presents an authentication request via the - UsernamePasswordAuthenticationToken with a - principal equal to - CasProcessingFilter.CAS_STATELESS_IDENTIFIER. - - Stateless clients are likely to be via remoting protocols such - as Hessian and Burlap. The BasicProcessingFilter is - still used in this case, but the remoting protocol client is expected - to present a username equal to the static string above, and a password - equal to a CAS service ticket. Clients should acquire a CAS service - ticket directly from the CAS server. - - Because remoting protocols have no way of presenting themselves - within the context of a HttpSession, it isn't - possible to rely on the HttpSession's - HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY - attribute to locate the CasAuthenticationToken. - Furthermore, because the CAS server invalidates a service ticket after - it has been validated by the TicketValidator, - presenting the same service ticket on subsequent requests will not - work. It is similarly very difficult to obtain a proxy-granting ticket - for a remoting protocol client, as they are often deployed on client - machines which rarely have HTTPS URLs that would be accessible to the - CAS server. - - One obvious option is to not use CAS at all for remoting - protocol clients. However, this would eliminate many of the desirable - features of CAS. - - As a middle-ground, the - CasAuthenticationProvider uses a - StatelessTicketCache. This is used solely for - requests with a principal equal to - CasProcessingFilter.CAS_STATELESS_IDENTIFIER. What - happens is the CasAuthenticationProvider will store - the resulting CasAuthenticationToken in the - StatelessTicketCache, keyed on the service ticket. - Accordingly, remoting protocol clients can present the same service - ticket and the CasAuthenticationProvider will not - need to contact the CAS server for validation (aside from the first - request). - - The other aspect of advanced CAS usage involves creating proxy - tickets from the proxy-granting ticket. As indicated above, we - recommend you use CAS' ProxyTicketReceptor to - receive these tickets. The ProxyTicketReceptor - provides a static method that enables you to obtain a proxy ticket by - presenting the proxy-granting IOU ticket. You can obtain the - proxy-granting IOU ticket by calling - CasAuthenticationToken.getProxyGrantingTicketIou(). - - It is hoped you find CAS integration easy and useful with Acegi - Security classes. Welcome to enterprise-wide single sign on! - - - - - Container Adapter Authentication - - - Overview - - Very early versions of Acegi Security exclusively used Container - Adapters for interfacing authentication with end users. Whilst this - worked well, it required considerable time to support multiple - container versions and the configuration itself was relatively - time-consuming for developers. For this reason the HTTP Form - Authentication and HTTP Basic Authentication approaches were - developed, and are today recommended for almost all - applications. - - Container Adapters enable Acegi Security to integrate directly - with the containers used to host end user applications. This - integration means that applications can continue to leverage the - authentication and authorization capabilities built into containers - (such as isUserInRole() and form-based or basic - authentication), whilst benefiting from the enhanced security - interception capabilities provided by Acegi Security (it should be - noted that Acegi Security also offers - ContextHolderAwareRequestWrapper to deliver - isUserInRole() and similar Servlet Specification - compatibility methods). - - The integration between a container and Acegi Security is - achieved through an adapter. The adapter provides a - container-compatible user authentication provider, and needs to return - a container-compatible user object. - - The adapter is instantiated by the container and is defined in a - container-specific configuration file. The adapter then loads a Spring - application context which defines the normal authentication manager - settings, such as the authentication providers that can be used to - authenticate the request. The application context is usually named - acegisecurity.xml and is placed in a - container-specific location. - - Acegi Security currently supports Jetty, Catalina (Tomcat), - JBoss and Resin. Additional container adapters can easily be - written - - - - Adapter Authentication Provider - - As is always the case, the container adapter generated - Authentication object still needs to be - authenticated by an AuthenticationManager when - requested to do so by the - AbstractSecurityInterceptor. The - AuthenticationManager needs to be certain the - adapter-provided Authentication object is valid and - was actually authenticated by a trusted adapter. - - Adapters create Authentication objects which - are immutable and implement the AuthByAdapter - interface. These objects store the hash of a key that is defined by - the adapter. This allows the Authentication object - to be validated by the AuthByAdapterProvider. This - authentication provider is defined as follows: - - <bean id="authByAdapterProvider" class="org.acegisecurity.adapters.AuthByAdapterProvider"> - <property name="key"><value>my_password</value></property> -</bean> - - The key must match the key that is defined in the - container-specific configuration file that starts the adapter. The - AuthByAdapterProvider automatically accepts as - valid any AuthByAdapter implementation that returns - the expected hash of the key. - - To reiterate, this means the adapter will perform the initial - authentication using providers such as - DaoAuthenticationProvider, returning an - AuthByAdapter instance that contains a hash code of - the key. Later, when an application calls a security interceptor - managed resource, the AuthByAdapter instance in the - SecurityContext in the - SecurityContextHolder will be tested by the - application's AuthByAdapterProvider. There is no - requirement for additional authentication providers such as - DaoAuthenticationProvider within the - application-specific application context, as the only type of - Authentication instance that will be presented by - the application is from the container adapter. - - Classloader issues are frequent with containers and the use of - container adapters illustrates this further. Each container requires a - very specific configuration. The installation instructions are - provided below. Once installed, please take the time to try the sample - application to ensure your container adapter is properly - configured. - - When using container adapters with the - DaoAuthenticationProvider, ensure you set its - forcePrincipalAsString property to - true. - - - - Jetty - - The following was tested with Jetty 4.2.18. - - $JETTY_HOME refers to the root of your Jetty - installation. - - Edit your $JETTY_HOME/etc/jetty.xml file so - the <Configure class> section has a new - addRealm call: - - - <Call name="addRealm"> - <Arg> - <New class="org.acegisecurity.adapters.jetty.JettyAcegiUserRealm"> - <Arg>Spring Powered Realm</Arg> - <Arg>my_password</Arg> - <Arg>etc/acegisecurity.xml</Arg> - </New> - </Arg> - </Call> - - - - Copy acegisecurity.xml into - $JETTY_HOME/etc. - - Copy the following files into - $JETTY_HOME/ext: - - aopalliance.jar - - - - commons-logging.jar - - - - spring.jar - - - - acegi-security-jetty-XX.jar - - - - commons-codec.jar - - - - burlap.jar - - - - hessian.jar - - - - None of the above JAR files (or - acegi-security-XX.jar) should be in your - application's WEB-INF/lib. The realm name indicated - in your web.xml does matter with Jetty. The - web.xml must express the same - <realm-name> as your - jetty.xml (in the example above, "Spring Powered - Realm"). - - - - JBoss - - The following was tested with JBoss 3.2.6. - - $JBOSS_HOME refers to the root of your JBoss - installation. - - There are two different ways of making spring context available - to the Jboss integration classes. - - The first approach is by editing your - $JBOSS_HOME/server/your_config/conf/login-config.xml - file so that it contains a new entry under the - <Policy> section: - - -<application-policy name = "SpringPoweredRealm"> - <authentication> - <login-module code = "org.acegisecurity.adapters.jboss.JbossAcegiLoginModule" - flag = "required"> - <module-option name = "appContextLocation">acegisecurity.xml</module-option> - <module-option name = "key">my_password</module-option> - </login-module> - </authentication> -</application-policy> - - - - Copy acegisecurity.xml into - $JBOSS_HOME/server/your_config/conf. - - In this configuration acegisecurity.xml - contains the spring context definition including all the - authentication manager beans. You have to bear in mind though, that - SecurityContext is created and destroyed on each - login request, so the login operation might become costly. - Alternatively, the second approach is to use Spring singleton - capabilities through - org.springframework.beans.factory.access.SingletonBeanFactoryLocator. - The required configuration for this approach is: - - -<application-policy name = "SpringPoweredRealm"> - <authentication> - <login-module code = "org.acegisecurity.adapters.jboss.JbossAcegiLoginModule" - flag = "required"> - <module-option name = "singletonId">springRealm</module-option> - <module-option name = "key">my_password</module-option> - <module-option name = "authenticationManager">authenticationManager</module-option> - </login-module> - </authentication> -</application-policy> - - - - In the above code fragment, - authenticationManager is a helper property that - defines the expected name of the - AuthenticationManager in case you have several - defined in the IoC container. The singletonId - property references a bean defined in a - beanRefFactory.xml file. This file needs to be - available from anywhere on the JBoss classpath, including - $JBOSS_HOME/server/your_config/conf. The - beanRefFactory.xml contains the following - declaration: - - -<beans> - <bean id="springRealm" singleton="true" lazy-init="true" class="org.springframework.context.support.ClassPathXmlApplicationContext"> - <constructor-arg> - <list> - <value>acegisecurity.xml</value> - </list> - </constructor-arg> - </bean> -</beans> - - - - Finally, irrespective of the configuration approach you need to - copy the following files into - $JBOSS_HOME/server/your_config/lib: - - aopalliance.jar - - - - spring.jar - - - - acegi-security-jboss-XX.jar - - - - commons-codec.jar - - - - burlap.jar - - - - hessian.jar - - - - None of the above JAR files (or - acegi-security-XX.jar) should be in your - application's WEB-INF/lib. The realm name indicated - in your web.xml does not matter with JBoss. - However, your web application's - WEB-INF/jboss-web.xml must express the same - <security-domain> as your - login-config.xml. For example, to match the above - example, your jboss-web.xml would look like - this: - - -<jboss-web> - <security-domain>java:/jaas/SpringPoweredRealm</security-domain> -</jboss-web> - - JBoss is a widely-used container adapter (mostly due to the need - to support legacy EJBs), so please let us know if you have any - difficulties. - - - - Resin - - The following was tested with Resin 3.0.6. - - $RESIN_HOME refers to the root of your Resin - installation. - - Resin provides several ways to support the container adapter. In - the instructions below we have elected to maximise consistency with - other container adapter configurations. This will allow Resin users to - simply deploy the sample application and confirm correct - configuration. Developers comfortable with Resin are naturally able to - use its capabilities to package the JARs with the web application - itself, and/or support single sign-on. - - Copy the following files into - $RESIN_HOME/lib: - - aopalliance.jar - - - - commons-logging.jar - - - - spring.jar - - - - acegi-security-resin-XX.jar - - - - commons-codec.jar - - - - burlap.jar - - - - hessian.jar - - - - Unlike the container-wide acegisecurity.xml - files used by other container adapters, each Resin web application - will contain its own - WEB-INF/resin-acegisecurity.xml file. Each web - application will also contain a resin-web.xml file - which Resin uses to start the container adapter: - - -<web-app> - <authenticator> - <type>org.acegisecurity.adapters.resin.ResinAcegiAuthenticator</type> - <init> - <app-context-location>WEB-INF/resin-acegisecurity.xml</app-context-location> - <key>my_password</key> - </init> - </authenticator> -</web-app> - - - - With the basic configuration provided above, none of the JAR - files listed (or acegi-security-XX.jar) should be - in your application's WEB-INF/lib. The realm name - indicated in your web.xml does not matter with - Resin, as the relevant authentication class is indicated by the - <authenticator> setting - - - - Tomcat - - The following was tested with Jakarta Tomcat 4.1.30 and - 5.0.19. - - $CATALINA_HOME refers to the root of your - Catalina (Tomcat) installation. - - Edit your $CATALINA_HOME/conf/server.xml file - so the <Engine> section contains only one - active <Realm> entry. An example realm - entry: - - <Realm className="org.acegisecurity.adapters.catalina.CatalinaAcegiUserRealm" - appContextLocation="conf/acegisecurity.xml" - key="my_password" /> - - Be sure to remove any other <Realm> - entry from your <Engine> section. - - Copy acegisecurity.xml into - $CATALINA_HOME/conf. - - Copy acegi-security-catalina-XX.jar into - $CATALINA_HOME/server/lib. - - Copy the following files into - $CATALINA_HOME/common/lib: - - - - aopalliance.jar - - - - spring.jar - - - - commons-codec.jar - - - - burlap.jar - - - - hessian.jar - - - - None of the above JAR files (or - acegi-security-XX.jar) should be in your - application's WEB-INF/lib. The realm name indicated - in your web.xml does not matter with - Catalina. - - We have received reports of problems using this Container - Adapter with Mac OS X. A work-around is to use a script such as - follows: - - #!/bin/sh -export CATALINA_HOME="/Library/Tomcat" -export JAVA_HOME="/Library/Java/Home" -cd / -$CATALINA_HOME/bin/startup.sh - - Finally, restart Tomcat. - - - - - - Authorization - - - The advanced authorization capabilities within Acegi Security - represent one of the most compelling reasons for its popularity. - Irrespective of how you choose to authenticate - whether using an Acegi - Security-provided mechanism and provider, or integrating with a - container or other non-Acegi Security authentication authority - you - will find the authorization services can be used within your application - in a consistent and simple way. - - In this part we'll explore the different - AbstractSecurityInterceptor implementations, which - were introduced in Part I. We then move on to explore how to fine-tune - authorization through use of domain access control lists. - - - - Common Authorization Concepts - - - Authorities - - As briefly mentioned in the Authentication section, all - Authentication implementations are required to - store an array of GrantedAuthority objects. These - represent the authorities that have been granted to the principal. The - GrantedAuthority objects are inserted into the - Authentication object by the - AuthenticationManager and are later read by - AccessDecisionManagers when making authorization - decisions. - - GrantedAuthority is an interface with only - one method: - - public String getAuthority(); - - This method allows AccessDecisionManagers to - obtain a precise String representation of the - GrantedAuthority. By returning a representation as - a String, a GrantedAuthority can - be easily "read" by most AccessDecisionManagers. If - a GrantedAuthority cannot be precisely represented - as a String, the - GrantedAuthority is considered "complex" and - getAuthority() must return - null. - - An example of a "complex" GrantedAuthority - would be an implementation that stores a list of operations and - authority thresholds that apply to different customer account numbers. - Representing this complex GrantedAuthority as a - String would be quite complex, and as a result the - getAuthority() method should return - null. This will indicate to any - AccessDecisionManager that it will need to - specifically support the GrantedAuthority - implementation in order to understand its contents. - - Acegi Security includes one concrete - GrantedAuthority implementation, - GrantedAuthorityImpl. This allows any - user-specified String to be converted into a - GrantedAuthority. All - AuthenticationProviders included with the security - architecture use GrantedAuthorityImpl to populate - the Authentication object. - - - - Pre-Invocation Handling - - The AccessDecisionManager is called by the - AbstractSecurityInterceptor and is responsible for - making final access control decisions. The - AccessDecisionManager interface contains three - methods: - - public void decide(Authentication authentication, Object object, ConfigAttributeDefinition config) throws AccessDeniedException; -public boolean supports(ConfigAttribute attribute); -public boolean supports(Class clazz); - - As can be seen from the first method, the - AccessDecisionManager is passed via method - parameters all information that is likely to be of value in assessing - an authorization decision. In particular, passing the secure - Object enables those arguments contained in the - actual secure object invocation to be inspected. For example, let's - assume the secure object was a MethodInvocation. It - would be easy to query the MethodInvocation for any - Customer argument, and then implement some sort of - security logic in the AccessDecisionManager to - ensure the principal is permitted to operate on that customer. - Implementations are expected to throw an - AccessDeniedException if access is denied. - - The supports(ConfigAttribute) method is - called by the AbstractSecurityInterceptor at - startup time to determine if the - AccessDecisionManager can process the passed - ConfigAttribute. The - supports(Class) method is called by a security - interceptor implementation to ensure the configured - AccessDecisionManager supports the type of secure - object that the security interceptor will present. - - Whilst users can implement their own - AccessDecisionManager to control all aspects of - authorization, Acegi Security includes several - AccessDecisionManager implementations that are - based on voting. Figure 4 illustrates the relevant classes. - - - - - - - - Figure 4: Voting Decision Manager - - - - Using this approach, a series of - AccessDecisionVoter implementations are polled on - an authorization decision. The - AccessDecisionManager then decides whether or not - to throw an AccessDeniedException based on its - assessment of the votes. - - The AccessDecisionVoter interface has three - methods: - - public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config); -public boolean supports(ConfigAttribute attribute); -public boolean supports(Class clazz); - - Concrete implementations return an int, with - possible values being reflected in the - AccessDecisionVoter static fields - ACCESS_ABSTAIN, ACCESS_DENIED - and ACCESS_GRANTED. A voting implementation will - return ACCESS_ABSTAIN if it has no opinion on an - authorization decision. If it does have an opinion, it must return - either ACCESS_DENIED or - ACCESS_GRANTED. - - There are three concrete - AccessDecisionManagers provided with Acegi Security - that tally the votes. The ConsensusBased - implementation will grant or deny access based on the consensus of - non-abstain votes. Properties are provided to control behavior in the - event of an equality of votes or if all votes are abstain. The - AffirmativeBased implementation will grant access - if one or more ACCESS_GRANTED votes were received - (ie a deny vote will be ignored, provided there was at least one grant - vote). Like the ConsensusBased implementation, - there is a parameter that controls the behavior if all voters abstain. - The UnanimousBased provider expects unanimous - ACCESS_GRANTED votes in order to grant access, - ignoring abstains. It will deny access if there is any - ACCESS_DENIED vote. Like the other implementations, - there is a parameter that controls the behaviour if all voters - abstain. - - It is possible to implement a custom - AccessDecisionManager that tallies votes - differently. For example, votes from a particular - AccessDecisionVoter might receive additional - weighting, whilst a deny vote from a particular voter may have a veto - effect. - - There are two concrete AccessDecisionVoter - implementations provided with Acegi Security. The - RoleVoter class will vote if any ConfigAttribute - begins with ROLE_. It will vote to grant access if - there is a GrantedAuthority which returns a - String representation (via the - getAuthority() method) exactly equal to one or more - ConfigAttributes starting with - ROLE_. If there is no exact match of any - ConfigAttribute starting with - ROLE_, the RoleVoter will vote - to deny access. If no ConfigAttribute begins with - ROLE_, the voter will abstain. - RoleVoter is case sensitive on comparisons as well - as the ROLE_ prefix. - - BasicAclEntryVoter is the other concrete - voter included with Acegi Security. It integrates with Acegi - Security's AclManager (discussed later). This voter - is designed to have multiple instances in the same application - context, such as: - - <bean id="aclContactReadVoter" class="org.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> - <ref local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/> - <ref local="org.acegisecurity.acl.basic.SimpleAclEntry.READ"/> - </list> - </property> -</bean> - -<bean id="aclContactDeleteVoter" class="org.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> - <ref local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/> - <ref local="org.acegisecurity.acl.basic.SimpleAclEntry.DELETE"/> - </list> - </property> -</bean> - - In the above example, you'd define - ACL_CONTACT_READ or - ACL_CONTACT_DELETE against some methods on a - MethodSecurityInterceptor or - AspectJSecurityInterceptor. When those methods are - invoked, the above applicable voter defined above would vote to grant - or deny access. The voter would look at the method invocation to - locate the first argument of type - sample.contact.Contact, and then pass that - Contact to the AclManager. The - AclManager will then return an access control list - (ACL) that applies to the current Authentication. - Assuming that ACL contains one of the listed - requirePermissions, the voter will vote to grant - access. If the ACL does not contain one of the permissions defined - against the voter, the voter will vote to deny access. - BasicAclEntryVoter is an important class as it - allows you to build truly complex applications with domain object - security entirely defined in the application context. If you're - interested in learning more about Acegi Security's ACL capabilities - and how best to apply them, please see the ACL and "After Invocation" - sections of this reference guide, and the Contacts sample - application. - - It is also possible to implement a custom - AccessDecisionVoter. Several examples are provided - in Acegi Security unit tests, including - ContactSecurityVoter and - DenyVoter. The - ContactSecurityVoter abstains from voting decisions - where a CONTACT_OWNED_BY_CURRENT_USER - ConfigAttribute is not found. If voting, it queries - the MethodInvocation to extract the owner of the - Contact object that is subject of the method call. - It votes to grant access if the Contact owner - matches the principal presented in the - Authentication object. It could have just as easily - compared the Contact owner with some - GrantedAuthority the - Authentication object presented. All of this is - achieved with relatively few lines of code and demonstrates the - flexibility of the authorization model. - - TODO: Remove references to the old ACL package when it's - deprecated, and have all references to the replacement package limited - to the chapter describing the new ACL implementation. - - - - After Invocation Handling - - Whilst the AccessDecisionManager is called by - the AbstractSecurityInterceptor before proceeding - with the secure object invocation, some applications need a way of - modifying the object actually returned by the secure object - invocation. Whilst you could easily implement your own AOP concern to - achieve this, Acegi Security provides a convenient hook that has - several concrete implementations that integrate with its ACL - capabilities. - - Figure 5 illustrates Acegi Security's - AfterInvocationManager and its concrete - implementations. - - - - - - - - Figure 5: After Invocation Implementation - - - - Like many other parts of Acegi Security, - AfterInvocationManager has a single concrete - implementation, AfterInvocationProviderManager, which - polls a list of AfterInvocationProviders. Each - AfterInvocationProvider is allowed to modify the - return object or throw an AccessDeniedException. - Indeed multiple providers can modify the object, as the result of the - previous provider is passed to the next in the list. Let's now - consider our ACL-aware implementations of - AfterInvocationProvider. - - Please be aware that if you're using - AfterInvocationManager, you will still need - configuration attributes that allow the - MethodSecurityInterceptor's - AccessDecisionManager to allow an operation. If - you're using the typical Acegi Security included - AccessDecisionManager implementations, having no - configuration attributes defined for a particular secure method - invocation will cause each AccessDecisionVoter to - abstain from voting. In turn, if the - AccessDecisionManager property - "allowIfAllAbstainDecisions" is - false, an AccessDeniedException - will be thrown. You may avoid this potential issue by either (i) - setting "allowIfAllAbstainDecisions" to - true (although this is generally not recommended) - or (ii) simply ensure that there is at least one configuration - attribute that an AccessDecisionVoter will vote to - grant access for. This latter (recommended) approach is usually - achieved through a ROLE_USER or - ROLE_AUTHENTICATED configuration attribute - - - ACL-Aware AfterInvocationProviders - - PLEASE NOTE: Acegi Security 1.0.3 contains a preview of a new - ACL module. The new ACL module is a significant rewrite of the - existing ACL module. The new module can be found under the - org.acegisecurity.acls package, with the old ACL - module under org.acegisecurity.acl. We encourage - users to consider testing with the new ACL module and build - applications with it. The old ACL module should be considered - deprecated and may be removed from a future release. The following - information relates to the new ACL package, and is thus - recommended. - - A common services layer method we've all written at one stage - or another looks like this: - - public Contact getById(Integer id); - - Quite often, only principals with permission to read the - Contact should be allowed to obtain it. In this - situation the AccessDecisionManager approach - provided by the AbstractSecurityInterceptor will - not suffice. This is because the identity of the - Contact is all that is available before the - secure object is invoked. The - AclAfterInvocationProvider delivers a solution, - and is configured as follows: - - <bean id="afterAclRead" class="org.acegisecurity.afterinvocation.AclEntryAfterInvocationProvider"> - <constructor-arg> - <ref bean="aclService"/> - </constructor-arg> - <constructor-arg> - <list> - <ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/> - <ref local="org.acegisecurity.acls.domain.BasePermission.READ"/> - </list> - </constructor-arg> -</bean> - - In the above example, the Contact will be - retrieved and passed to the - AclEntryAfterInvocationProvider. The provider - will thrown an AccessDeniedException if one of - the listed requirePermissions is not held by the - Authentication. The - AclEntryAfterInvocationProvider queries the - AclService to determine the ACL that applies for - this domain object to this Authentication. - - Similar to the - AclEntryAfterInvocationProvider is - AclEntryAfterInvocationCollectionFilteringProvider. - It is designed to remove Collection or array - elements for which a principal does not have access. It never thrown - an AccessDeniedException - simply silently - removes the offending elements. The provider is configured as - follows: - - <bean id="afterAclCollectionRead" class="org.acegisecurity.afterinvocation.AclEntryAfterInvocationCollectionFilteringProvider"> - <constructor-arg> - <ref bean="aclService"/> - </constructor-arg> - <constructor-arg> - <list> - <ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/> - <ref local="org.acegisecurity.acls.domain.BasePermission.READ"/> - </list> - </constructor-arg> -</bean> - - As you can imagine, the returned Object - must be a Collection or array for this provider - to operate. It will remove any element if the - AclManager indicates the - Authentication does not hold one of the listed - requirePermissions. - - The Contacts sample application demonstrates these two - AfterInvocationProviders. - - - - ACL-Aware AfterInvocationProviders (old ACL module) - - PLEASE NOTE: Acegi Security 1.0.3 contains a preview of a new - ACL module. The new ACL module is a significant rewrite of the - existing ACL module. The new module can be found under the - org.acegisecurity.acls package, with the old ACL - module under org.acegisecurity.acl. We encourage - users to consider testing with the new ACL module and build - applications with it. The old ACL module should be considered - deprecated and may be removed from a future release. - - A common services layer method we've all written at one stage - or another looks like this: - - public Contact getById(Integer id); - - Quite often, only principals with permission to read the - Contact should be allowed to obtain it. In this - situation the AccessDecisionManager approach - provided by the AbstractSecurityInterceptor will - not suffice. This is because the identity of the - Contact is all that is available before the - secure object is invoked. The - BasicAclAfterInvocationProvider delivers a - solution, and is configured as follows: - - <bean id="afterAclRead" class="org.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationProvider"> - <property name="aclManager"><ref local="aclManager"/></property> - <property name="requirePermission"> - <list> - <ref local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/> - <ref local="org.acegisecurity.acl.basic.SimpleAclEntry.READ"/> - </list> - </property> -</bean> - - In the above example, the Contact will be - retrieved and passed to the - BasicAclEntryAfterInvocationProvider. The - provider will thrown an AccessDeniedException if - one of the listed requirePermissions is not held - by the Authentication. The - BasicAclEntryAfterInvocationProvider queries the - AclManager to determine the ACL that applies for - this domain object to this Authentication. - - Similar to the - BasicAclEntryAfterInvocationProvider is - BasicAclEntryAfterInvocationCollectionFilteringProvider. - It is designed to remove Collection or array - elements for which a principal does not have access. It never thrown - an AccessDeniedException - simply silently - removes the offending elements. The provider is configured as - follows: - - <bean id="afterAclCollectionRead" class="org.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationCollectionFilteringProvider"> - <property name="aclManager"><ref local="aclManager"/></property> - <property name="requirePermission"> - <list> - <ref local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/> - <ref local="org.acegisecurity.acl.basic.SimpleAclEntry.READ"/> - </list> - </property> -</bean> - - As you can imagine, the returned Object - must be a Collection or array for this provider - to operate. It will remove any element if the - AclManager indicates the - Authentication does not hold one of the listed - requirePermissions. - - The Contacts sample application demonstrates these two - AfterInvocationProviders. - - - - - Authorization Tag Libraries - - AuthorizeTag is used to include content if - the current principal holds certain - GrantedAuthoritys. - - The following JSP fragment illustrates how to use the - AuthorizeTag: - - <authz:authorize ifAllGranted="ROLE_SUPERVISOR"> - <td> - <A HREF="del.htm?id=<c:out value="${contact.id}"/>">Del</A> - </td> -</authz:authorize> - - This tag would cause the tag's body to be output if the - principal has been granted ROLE_SUPERVISOR. - - The authz:authorize tag declares the - following attributes: - - - - ifAllGranted: All the listed roles must - be granted for the tag to output its body. - - - - ifAnyGranted: Any of the listed roles - must be granted for the tag to output its body. - - - - ifNotGranted: None of the listed roles - must be granted for the tag to output its body. - - - - You'll note that in each attribute you can list multiple roles. - Simply separate the roles using a comma. The - authorize tag ignores whitespace in - attributes. - - The tag library logically ANDs all of it's parameters together. - This means that if you combine two or more attributes, all attributes - must be true for the tag to output it's body. Don't add an - ifAllGranted="ROLE_SUPERVISOR", followed by an - ifNotGranted="ROLE_SUPERVISOR", or you'll be - surprised to never see the tag's body. - - By requiring all attributes to return true, the authorize tag - allows you to create more complex authorization scenarios. For - example, you could declare an - ifAllGranted="ROLE_SUPERVISOR" and an - ifNotGranted="ROLE_NEWBIE_SUPERVISOR" in the same - tag, in order to prevent new supervisors from seeing the tag body. - However it would no doubt be simpler to use - ifAllGranted="ROLE_EXPERIENCED_SUPERVISOR" rather - than inserting NOT conditions into your design. - - One last item: the tag verifies the authorizations in a specific - order: first ifNotGranted, then - ifAllGranted, and finally, if - AnyGranted. - - AccessControlListTag is used to include - content if the current principal has an ACL to the indicated domain - object. - - The following JSP fragment illustrates how to use the - AccessControlListTag: - - <authz:accesscontrollist domainObject="${contact}" hasPermission="8,16"> - <td><A HREF="<c:url value="del.htm"><c:param name="contactId" value="${contact.id}"/></c:url>">Del</A></td> -</authz:accesscontrollist> - - This tag would cause the tag's body to be output if the - principal holds either permission 16 or permission 1 for the "contact" - domain object. The numbers are actually integers that are used with - BasePermission bit masking. Please refer to the ACL - section of this reference guide to understand more about the ACL - capabilities of Acegi Security. - - AclTag is part of the old ACL module and - should be considered deprecated. For the sake of historical reference, - works exactly the samae as - AccessControlListTag. - - - - - Secure Object Implementations - - - AOP Alliance (MethodInvocation) Security Interceptor - - To secure MethodInvocations, developers - simply add a properly configured - MethodSecurityInterceptor into the application - context. Next the beans requiring security are chained into the - interceptor. This chaining is accomplished using Spring’s - ProxyFactoryBean or - BeanNameAutoProxyCreator, as commonly used by many - other parts of Spring (refer to the sample application for examples). - Alternatively, Acegi Security provides a - MethodDefinitionSourceAdvisor which may be used - with Spring's DefaultAdvisorAutoProxyCreator to - automatically chain the security interceptor in front of any beans - defined against the MethodSecurityInterceptor. The - MethodSecurityInterceptor itself is configured as - follows: - - <bean id="bankManagerSecurity" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor"> - <property name="validateConfigAttributes"><value>true</value></property> - <property name="authenticationManager"><ref bean="authenticationManager"/></property> - <property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property> - <property name="runAsManager"><ref bean="runAsManager"/></property> - <property name="afterInvocationManager"><ref bean="afterInvocationManager"/></property> - <property name="objectDefinitionSource"> - <value> - org.acegisecurity.context.BankManager.delete*=ROLE_SUPERVISOR,RUN_AS_SERVER - org.acegisecurity.context.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_AS_SERVER - </value> - </property> -</bean> - - As shown above, the MethodSecurityInterceptor - is configured with a reference to an - AuthenticationManager, - AccessDecisionManager and - RunAsManager, which are each discussed in separate - sections below. In this case we've also defined an - AfterInvocationManager, although this is entirely - optional. The MethodSecurityInterceptor is also - configured with configuration attributes that apply to different - method signatures. A full discussion of configuration attributes is - provided in the High Level Design section of this document. - - The MethodSecurityInterceptor can be - configured with configuration attributes in three ways. The first is - via a property editor and the application context, which is shown - above. The second is via defining the configuration attributes in your - source code using Jakarta Commons Attributes or Java 5 Annotations. - The third is via writing your own - ObjectDefinitionSource, although this is beyond the - scope of this document. Irrespective of the approach used, the - ObjectDefinitionSource is responsible for returning - a ConfigAttributeDefinition object that contains - all of the configuration attributes associated with a single secure - method. - - It should be noted that the - MethodSecurityInterceptor.setObjectDefinitionSource() - method actually expects an instance of - MethodDefinitionSource. This is a marker interface - which subclasses ObjectDefinitionSource. It simply - denotes the ObjectDefinitionSource understands - MethodInvocations. In the interests of simplicity - we'll continue to refer to the - MethodDefinitionSource as an - ObjectDefinitionSource, as the distinction is of - little relevance to most users of the - MethodSecurityInterceptor. - - If using the application context property editor approach (as - shown above), commas are used to delimit the different configuration - attributes that apply to a given method pattern. Each configuration - attribute is assigned into its own SecurityConfig - object. The SecurityConfig object is discussed in - the High Level Design section. - - If you are using the Jakarta Commons Attributes approach, your - bean context will be configured differently: - - <bean id="attributes" class="org.springframework.metadata.commons.CommonsAttributes"/> -<bean id="objectDefinitionSource" class="org.acegisecurity.intercept.method.MethodDefinitionAttributes"> - <property name="attributes"><ref local="attributes"/></property> -</bean> - -<bean id="bankManagerSecurity" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor"> - <property name="validateConfigAttributes"><value>false</value></property> - <property name="authenticationManager"><ref bean="authenticationManager"/></property> - <property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property> - <property name="runAsManager"><ref bean="runAsManager"/></property> - <property name="objectDefinitionSource"><ref bean="objectDefinitionSource"/></property> -</bean> - - In addition, your source code will contain Jakarta Commons - Attributes tags that refer to a concrete implementation of - ConfigAttribute. The following example uses the - SecurityConfig implementation to represent the - configuration attributes, and results in the same security - configuration as provided by the property editor approach - above: - - public interface BankManager { - - /** - * @@SecurityConfig("ROLE_SUPERVISOR") - * @@SecurityConfig("RUN_AS_SERVER") - */ - public void deleteSomething(int id); - - /** - * @@SecurityConfig("ROLE_SUPERVISOR") - * @@SecurityConfig("RUN_AS_SERVER") - */ - public void deleteAnother(int id); - - /** - * @@SecurityConfig("ROLE_TELLER") - * @@SecurityConfig("ROLE_SUPERVISOR") - * @@SecurityConfig("BANKSECURITY_CUSTOMER") - * @@SecurityConfig("RUN_AS_SERVER") - */ - public float getBalance(int id); -} - - If you are using the Acegi Security Java 5 Annotations approach, - your bean context will be configured as follows: - - <bean id="attributes" class="org.acegisecurity.annotation.SecurityAnnotationAttributes"/> -<bean id="objectDefinitionSource" class="org.acegisecurity.intercept.method.MethodDefinitionAttributes"> - <property name="attributes"><ref local="attributes"/></property> -</bean> - -<bean id="bankManagerSecurity" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor"> - <property name="validateConfigAttributes"><value>false</value></property> - <property name="authenticationManager"><ref bean="authenticationManager"/></property> - <property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property> - <property name="runAsManager"><ref bean="runAsManager"/></property> - <property name="objectDefinitionSource"><ref bean="objectDefinitionSource"/></property> -</bean> - - In addition, your source code will contain Acegi Java 5 Security - Annotations that represent the ConfigAttribute. The - following example uses the @Secured annotations to - represent the configuration attributes, and results in the same - security configuration as provided by the property editor - approach: - - import org.acegisecurity.annotation.Secured; - -public interface BankManager { - - /** - * Delete something - */ - @Secured({"ROLE_SUPERVISOR","RUN_AS_SERVER" }) - public void deleteSomething(int id); - - /** - * Delete another - */ - @Secured({"ROLE_SUPERVISOR","RUN_AS_SERVER" }) - public void deleteAnother(int id); - - /** - * Get balance - */ - @Secured({"ROLE_TELLER","ROLE_SUPERVISOR","BANKSECURITY_CUSTOMER","RUN_AS_SERVER" }) - public float getBalance(int id); -} - - You might have noticed the - validateConfigAttributes property in the above - MethodSecurityInterceptor examples. When set to - true (the default), at startup time the - MethodSecurityInterceptor will evaluate if the - provided configuration attributes are valid. It does this by checking - each configuration attribute can be processed by either the - AccessDecisionManager or the - RunAsManager. If neither of these can process a - given configuration attribute, an exception is thrown. If using the - Jakarta Commons Attributes method of configuration, you should set - validateConfigAttributes to - false. - - Please note that when using - BeanNameAutoProxyCreator to create the required - proxy for security, the configuration must contain the property - proxyTargetClass set to true. - Otherwise, the method passed to - MethodSecurityInterceptor.invoke is the proxy's - caller, not the proxy's target. Note that this introduces a - requirement on CGLIB. See an example of using - BeanNameAutoProxyCreator below: - - <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> - <property name="interceptorNames"> - <list><value>methodSecurityInterceptor</value></list> - </property> - <property name="beanNames"> - <list><value>targetObjectName</value></list> - </property> - <property name="proxyTargetClass" value="true"/> -</bean> - - - - AspectJ (JoinPoint) Security Interceptor - - The AspectJ security interceptor is very similar to the AOP - Alliance security interceptor discussed in the previous section. - Indeed we will only discuss the differences in this section. - - The AspectJ interceptor is named - AspectJSecurityInterceptor. Unlike the AOP Alliance - security interceptor, which relies on the Spring application context - to weave in the security interceptor via proxying, the - AspectJSecurityInterceptor is weaved in via the - AspectJ compiler. It would not be uncommon to use both types of - security interceptors in the same application, with - AspectJSecurityInterceptor being used for domain - object instance security and the AOP Alliance - MethodSecurityInterceptor being used for services - layer security. - - Let's first consider how the - AspectJSecurityInterceptor is configured in the - Spring application context: - - <bean id="bankManagerSecurity" class="org.acegisecurity.intercept.method.aspectj.AspectJSecurityInterceptor"> - <property name="validateConfigAttributes"><value>true</value></property> - <property name="authenticationManager"><ref bean="authenticationManager"/></property> - <property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property> - <property name="runAsManager"><ref bean="runAsManager"/></property> - <property name="afterInvocationManager"><ref bean="afterInvocationManager"/></property> - <property name="objectDefinitionSource"> - <value> - org.acegisecurity.context.BankManager.delete*=ROLE_SUPERVISOR,RUN_AS_SERVER - org.acegisecurity.context.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_AS_SERVER - </value> - </property> -</bean> - - As you can see, aside from the class name, the - AspectJSecurityInterceptor is exactly the same as - the AOP Alliance security interceptor. Indeed the two interceptors can - share the same objectDefinitionSource, as the - ObjectDefinitionSource works with - java.lang.reflect.Methods rather than an AOP - library-specific class. Of course, your access decisions have access - to the relevant AOP library-specific invocation (ie - MethodInvocation or JoinPoint) - and as such can consider a range of addition criteria when making - access decisions (such as method arguments). - - Next you'll need to define an AspectJ aspect. - For example: - - package org.acegisecurity.samples.aspectj; - -import org.acegisecurity.intercept.method.aspectj.AspectJSecurityInterceptor; -import org.acegisecurity.intercept.method.aspectj.AspectJCallback; -import org.springframework.beans.factory.InitializingBean; - -public aspect DomainObjectInstanceSecurityAspect implements InitializingBean { - - private AspectJSecurityInterceptor securityInterceptor; - - pointcut domainObjectInstanceExecution(): target(PersistableEntity) - && execution(public * *(..)) && !within(DomainObjectInstanceSecurityAspect); - - Object around(): domainObjectInstanceExecution() { - if (this.securityInterceptor != null) { - AspectJCallback callback = new AspectJCallback() { - public Object proceedWithObject() { - return proceed(); - } - }; - return this.securityInterceptor.invoke(thisJoinPoint, callback); - } else { - return proceed(); - } - } - - public AspectJSecurityInterceptor getSecurityInterceptor() { - return securityInterceptor; - } - - public void setSecurityInterceptor(AspectJSecurityInterceptor securityInterceptor) { - this.securityInterceptor = securityInterceptor; - } - - public void afterPropertiesSet() throws Exception { - if (this.securityInterceptor == null) - throw new IllegalArgumentException("securityInterceptor required"); - } -} - - In the above example, the security interceptor will be applied - to every instance of PersistableEntity, which is an - abstract class not shown (you can use any other class or - pointcut expression you like). For those curious, - AspectJCallback is needed because the - proceed(); statement has special meaning only - within an around() body. The - AspectJSecurityInterceptor calls this anonymous - AspectJCallback class when it wants the target - object to continue. - - You will need to configure Spring to load the aspect and wire it - with the AspectJSecurityInterceptor. A bean - declaration which achieves this is shown below: - - -<bean id="domainObjectInstanceSecurityAspect" - class="org.acegisecurity.samples.aspectj.DomainObjectInstanceSecurityAspect" - factory-method="aspectOf"> - <property name="securityInterceptor"><ref bean="aspectJSecurityInterceptor"/></property> -</bean> - - - - That's it! Now you can create your beans from anywhere within - your application, using whatever means you think fit (eg new - Person();) and they will have the security interceptor - applied. - - - - FilterInvocation Security Interceptor - - To secure FilterInvocations, developers need - to add a filter to their web.xml that delegates to - the FilterSecurityInterceptor. A typical - configuration example is provided below: - - <filter> - <filter-name>Acegi HTTP Request Security Filter</filter-name> - <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class> - <init-param> - <param-name>targetClass</param-name> - <param-value>org.acegisecurity.intercept.web.FilterSecurityInterceptor</param-value> - </init-param> -</filter> - -<filter-mapping> - <filter-name>Acegi HTTP Request Security Filter</filter-name> - <url-pattern>/*</url-pattern> -</filter-mapping> - - Notice that the filter is actually a - FilterToBeanProxy. Most of the filters used by - Acegi Security use this class. Refer to the Filters section to learn - more about this bean. - - In the application context you will need to configure three - beans: - - <bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter"> - <property name="authenticationEntryPoint"><ref local="authenticationEntryPoint"/></property> -</bean> - -<bean id="authenticationEntryPoint" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint"> - <property name="loginFormUrl"><value>/acegilogin.jsp</value></property> - <property name="forceHttps"><value>false</value></property> -</bean> - -<bean id="filterSecurityInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor"> - <property name="authenticationManager"><ref bean="authenticationManager"/></property> - <property name="accessDecisionManager"><ref bean="accessDecisionManager"/></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 - </value> - </property> -</bean> - - The ExceptionTranslationFilter provides - the bridge between Java exceptions and HTTP responses. It is solely - concerned with maintaining the user interface. This filter does not do - any actual security enforcement. If an - AuthenticationException is detected, - the filter will call the AuthenticationEntryPoint to commence the - authentication process (e.g. a user login). - - The AuthenticationEntryPoint will be called - if the user requests a secure HTTP resource but they are not - authenticated. The class handles presenting the appropriate response - to the user so that authentication can begin. Three concrete - implementations are provided with Acegi Security: - AuthenticationProcessingFilterEntryPoint for - commencing a form-based authentication, - BasicProcessingFilterEntryPoint for commencing a - HTTP Basic authentication process, and - CasProcessingFilterEntryPoint for commencing a - JA-SIG Central Authentication Service (CAS) login. The - AuthenticationProcessingFilterEntryPoint and - CasProcessingFilterEntryPoint have optional - properties related to forcing the use of HTTPS, so please refer to the - JavaDocs if you require this. - - FilterSecurityInterceptor is responsible for - handling the security of HTTP resources. Like any other security - interceptor, it requires a reference to an - AuthenticationManager and an - AccessDecisionManager, which are both discussed in - separate sections below. The - FilterSecurityInterceptor is also configured with - configuration attributes that apply to different HTTP URL requests. A - full discussion of configuration attributes is provided in the High - Level Design section of this document. - - The FilterSecurityInterceptor can be - configured with configuration attributes in two ways. The first is via - a property editor and the application context, which is shown above. - The second is via writing your own - ObjectDefinitionSource, although this is beyond the - scope of this document. Irrespective of the approach used, the - ObjectDefinitionSource is responsible for returning - a ConfigAttributeDefinition object that contains - all of the configuration attributes associated with a single secure - HTTP URL. - - It should be noted that the - FilterSecurityInterceptor.setObjectDefinitionSource() - method actually expects an instance of - FilterInvocationDefinitionSource. This is a marker - interface which subclasses ObjectDefinitionSource. - It simply denotes the ObjectDefinitionSource - understands FilterInvocations. In the interests of - simplicity we'll continue to refer to the - FilterInvocationDefinitionSource as an - ObjectDefinitionSource, as the distinction is of - little relevance to most users of the - FilterSecurityInterceptor. - - If using the application context property editor approach (as - shown above), commas are used to delimit the different configuration - attributes that apply to each HTTP URL. Each configuration attribute - is assigned into its own SecurityConfig object. The - SecurityConfig object is discussed in the High - Level Design section. The ObjectDefinitionSource - created by the property editor, - FilterInvocationDefinitionSource, matches - configuration attributes against FilterInvocations - based on expression evaluation of the request URL. Two standard - expression syntaxes are supported. The default is to treat all - expressions as regular expressions. Alternatively, the presence of a - PATTERN_TYPE_APACHE_ANT directive will cause all - expressions to be treated as Apache Ant paths. It is not possible to - mix expression syntaxes within the same definition. For example, the - earlier configuration could be generated using Apache Ant paths as - follows: - - <bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor"> - <property name="authenticationManager"><ref bean="authenticationManager"/></property> - <property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property> - <property name="runAsManager"><ref bean="runAsManager"/></property> - <property name="objectDefinitionSource"> - <value> - CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON - PATTERN_TYPE_APACHE_ANT - /secure/super/**=ROLE_WE_DONT_HAVE - /secure/**=ROLE_SUPERVISOR,ROLE_TELLER - </value> - </property> -</bean> - - Irrespective of the type of expression syntax used, expressions - are always evaluated in the order they are defined. Thus it is - important that more specific expressions are defined higher in the - list than less specific expressions. This is reflected in our example - above, where the more specific /secure/super/ - pattern appears higher than the less specific - /secure/ pattern. If they were reversed, the - /secure/ pattern would always match and the - /secure/super/ pattern would never be - evaluated. - - The special keyword - CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON causes - the FilterInvocationDefinitionSource to - automatically convert a request URL to lowercase before comparison - against the expressions. Whilst by default the case of the request URL - is not converted, it is generally recommended to use - CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON and - write each expression assuming lowercase. - - As with other security interceptors, the - validateConfigAttributes property is observed. When - set to true (the default), at startup time the - FilterSecurityInterceptor will evaluate if the - provided configuration attributes are valid. It does this by checking - each configuration attribute can be processed by either the - AccessDecisionManager or the - RunAsManager. If neither of these can process a - given configuration attribute, an exception is thrown. - - - - - Domain Object Security - -
- Overview - - PLEASE NOTE: Acegi Security 1.0.3 contains a preview of a new - ACL module. The new ACL module is a significant rewrite of the - existing ACL module. The new module can be found under the - org.acegisecurity.acls package, with the old ACL - module under org.acegisecurity.acl. We encourage - users to consider testing with the new ACL module and build - applications with it. The old ACL module should be considered - deprecated and may be removed from a future release. - - Complex applications often will find the need to define access - permissions not simply at a web request or method invocation level. - Instead, security decisions need to comprise both who - (Authentication), where - (MethodInvocation) and what - (SomeDomainObject). In other words, authorization - decisions also need to consider the actual domain object instance - subject of a method invocation. - - Imagine you're designing an application for a pet clinic. There - will be two main groups of users of your Spring-based application: - staff of the pet clinic, as well as the pet clinic's customers. The - staff will have access to all of the data, whilst your customers will - only be able to see their own customer records. To make it a little - more interesting, your customers can allow other users to see their - customer records, such as their "puppy preschool "mentor or president - of their local "Pony Club". Using Acegi Security as the foundation, - you have several approaches that can be used: - - Write your business methods to enforce the security. You - could consult a collection within the - Customer domain object instance to determine - which users have access. By using the - SecurityContextHolder.getContext().getAuthentication(), - you'll be able to access the Authentication - object. - - - - Write an AccessDecisionVoter to enforce - the security from the GrantedAuthority[]s - stored in the Authentication object. This - would mean your AuthenticationManager would - need to populate the Authentication with - custom GrantedAuthority[]s representing each - of the Customer domain object instances the - principal has access to. - - - - Write an AccessDecisionVoter to enforce - the security and open the target Customer - domain object directly. This would mean your voter needs access - to a DAO that allows it to retrieve the - Customer object. It would then access the - Customer object's collection of approved - users and make the appropriate decision. - - - - Each one of these approaches is perfectly legitimate. However, - the first couples your authorization checking to your business code. - The main problems with this include the enhanced difficulty of unit - testing and the fact it would be more difficult to reuse the - Customer authorization logic elsewhere. Obtaining - the GrantedAuthority[]s from the - Authentication object is also fine, but will not - scale to large numbers of Customers. If a user - might be able to access 5,000 Customers (unlikely - in this case, but imagine if it were a popular vet for a large Pony - Club!) the amount of memory consumed and time required to construct - the Authentication object would be undesirable. The - final method, opening the Customer directly from - external code, is probably the best of the three. It achieves - separation of concerns, and doesn't misuse memory or CPU cycles, but - it is still inefficient in that both the - AccessDecisionVoter and the eventual business - method itself will perform a call to the DAO responsible for - retrieving the Customer object. Two accesses per - method invocation is clearly undesirable. In addition, with every - approach listed you'll need to write your own access control list - (ACL) persistence and business logic from scratch. - - Fortunately, there is another alternative, which we'll talk - about below. -
- -
- Key Concepts - - The org.acegisecurity.acls package should be consulted for its - major interfaces. The key interfaces are: - - - - Acl: Every domain object has one and only - one Acl object, which internally holds the - AccessControlEntrys as well as knows the owner - of the Acl. An Acl does not refer directly to - the domain object, but instead to an - ObjectIdentity. - - - - AccessControlEntry: An - Acl holds multiple AccessControlEntrys, which - are often abbreviated as ACEs in the framework. Each ACE refers to - a specific tuple of Permission, - Sid and Acl. An ACE can also - be granting or non-granting and contain audit settings. - - - - Permission: A permission represents an - immutable particular bit mask, and offers convenience functions - for bit masking and outputting information. - - - - Sid: The ACL module needs to refer to - principals and GrantedAuthority[]s. A level of - indirection is provided by the Sid interface. - Common classes include PrincipalSid (to - represent the principal inside an - Authentication object) and - GrantedAuthoritySid. - - - - ObjectIdentity: Each domain object is - represented internally within the ACL module by an - ObjectIdentity. - - - - AclService: Retrieves the - Acl applicable for a given - ObjectIdentity. - - - - MutableAclService: Allows a modified - Acl to be presented for persistence. It is not - essential to use this interface if you do not wish. - - - - The ACL module was based on extensive feedback from the user - community following real-world use of the original ACL module. This - feedback resulted in a rearchitecture of the ACL module to offer - significantly enhanced performance (particularly in the area of - database retrieval), significantly better encapsulation, higher - cohesion, and enhanced customisation points. - - The Contacts Sample that ships with Acegi Security 1.0.3 offers - a demonstration of the new ACL module. Converting Contacts from using - the old module to the new module was relatively simple, and users of - the old ACL module will likely find their applications can be modified - with relatively little work. - - We will document the new ACL module more fully with a subsequent - release. Please note that the new ACL module should be considered a - preview only (ie do not use in production without proper prior - testing), and there is a small chance there may be changes between - 1.0.3 and 1.1.0 when it will become final. Nevertheless, - compatibility-affecting changes are considered quite unlikely, - especially given the module is already based on several years of - feedback from users of the original ACL module. -
-
- - - Domain Object Security (old ACL module) - -
- Overview - - PLEASE NOTE: Acegi Security 1.0.3 contains a preview of a new - ACL module. The new ACL module is a significant rewrite of the - existing ACL module. The new module can be found under the - org.acegisecurity.acls package, with the old ACL - module under org.acegisecurity.acl. We encourage - users to consider testing with the new ACL module and build - applications with it. The old ACL module should be considered - deprecated and may be removed from a future release. - - Complex applications often will find the need to define access - permissions not simply at a web request or method invocation level. - Instead, security decisions need to comprise both who - (Authentication), where - (MethodInvocation) and what - (SomeDomainObject). In other words, authorization - decisions also need to consider the actual domain object instance - subject of a method invocation. - - Imagine you're designing an application for a pet clinic. There - will be two main groups of users of your Spring-based application: - staff of the pet clinic, as well as the pet clinic's customers. The - staff will have access to all of the data, whilst your customers will - only be able to see their own customer records. To make it a little - more interesting, your customers can allow other users to see their - customer records, such as their "puppy preschool "mentor or president - of their local "Pony Club". Using Acegi Security as the foundation, - you have several approaches that can be used: - - Write your business methods to enforce the security. You - could consult a collection within the - Customer domain object instance to determine - which users have access. By using the - SecurityContextHolder.getContext().getAuthentication(), - you'll be able to access the Authentication - object. - - - - Write an AccessDecisionVoter to enforce - the security from the GrantedAuthority[]s - stored in the Authentication object. This - would mean your AuthenticationManager would - need to populate the Authentication with - custom GrantedAuthority[]s representing each - of the Customer domain object instances the - principal has access to. - - - - Write an AccessDecisionVoter to enforce - the security and open the target Customer - domain object directly. This would mean your voter needs access - to a DAO that allows it to retrieve the - Customer object. It would then access the - Customer object's collection of approved - users and make the appropriate decision. - - - - Each one of these approaches is perfectly legitimate. However, - the first couples your authorization checking to your business code. - The main problems with this include the enhanced difficulty of unit - testing and the fact it would be more difficult to reuse the - Customer authorization logic elsewhere. Obtaining - the GrantedAuthority[]s from the - Authentication object is also fine, but will not - scale to large numbers of Customers. If a user - might be able to access 5,000 Customers (unlikely - in this case, but imagine if it were a popular vet for a large Pony - Club!) the amount of memory consumed and time required to construct - the Authentication object would be undesirable. The - final method, opening the Customer directly from - external code, is probably the best of the three. It achieves - separation of concerns, and doesn't misuse memory or CPU cycles, but - it is still inefficient in that both the - AccessDecisionVoter and the eventual business - method itself will perform a call to the DAO responsible for - retrieving the Customer object. Two accesses per - method invocation is clearly undesirable. In addition, with every - approach listed you'll need to write your own access control list - (ACL) persistence and business logic from scratch. - - Fortunately, there is another alternative, which we'll talk - about below. -
- -
- Basic ACL Package - - Please note that our Basic ACL services are currently being - refactored. We expect release 1.1.0 will contain this new code. - Planned code is already in the Acegi Security Subversion sandbox, so - please check there if you have a new application requiring ACLs or are - in the planning stages. The Basic ACL services will be deprecated from - release 1.1.0. - - The org.acegisecurity.acl package is very - simple, comprising only a handful of interfaces and a single class, as - shown in Figure 6. It provides the basic foundation for access control - list (ACL) lookups. - - - - - - - - Figure 6: Access Control List Manager - - - - The central interface is AclManager, which is - defined by two methods: - - public AclEntry[] getAcls(java.lang.Object domainInstance); -public AclEntry[] getAcls(java.lang.Object domainInstance, Authentication authentication); - - AclManager is intended to be used as a - collaborator against your business objects, or, more desirably, - AccessDecisionVoters. This means you use Spring's - normal ApplicationContext features to wire up your - AccessDecisionVoter (or business method) with an - AclManager. Consideration was given to placing the - ACL information in the ContextHolder, but it was - felt this would be inefficient both in terms of memory usage as well - as the time spent loading potentially unused ACL information. The - trade-off of needing to wire up a collaborator for those objects - requiring ACL information is rather minor, particularly in a - Spring-managed application. - - The first method of the AclManager will - return all ACLs applying to the domain object instance passed to it. - The second method does the same, but only returns those ACLs which - apply to the passed Authentication object. - - The AclEntry interface returned by - AclManager is merely a marker interface. You will - need to provide an implementation that reflects that ACL permissions - for your application. - - Rounding out the org.acegisecurity.acl - package is an AclProviderManager class, with a - corresponding AclProvider interface. - AclProviderManager is a concrete implementation of - AclManager, which iterates through registered - AclProviders. The first - AclProvider that indicates it can authoritatively - provide ACL information for the presented domain object instance will - be used. This is very similar to the - AuthenticationProvider interface used for - authentication. - - With this background, let's now look at a usable ACL - implementation. - - Acegi Security includes a production-quality ACL provider - implementation, which is shown in Figure 7. - - - - - - - - Figure 7: Basic ACL Manager - - - - The implementation is based on integer masking, which is - commonly used for ACL permissions given its flexibility and speed. - Anyone who has used Unix's chmod command will know - all about this type of permission masking (eg chmod - 777). You'll find the classes and interfaces for the integer - masking ACL package under - org.acegisecurity.acl.basic. - - Extending the AclEntry interface is a - BasicAclEntry interface, with the main methods - shown below: - - public AclObjectIdentity getAclObjectIdentity(); -public AclObjectIdentity getAclObjectParentIdentity(); -public int getMask(); -public java.lang.Object getRecipient(); - - As shown, each BasicAclEntry has four main - properties. The mask is the integer that represents - the permissions granted to the recipient. The - aclObjectIdentity is able to identify the domain - object instance for which the ACL applies, and the - aclObjectParentIdentity optionally specifies the - parent of the domain object instance. Multiple - BasicAclEntrys usually exist against a single - domain object instance, and as suggested by the parent identity - property, permissions granted higher in the object hierarchy will - trickle down and be inherited (unless blocked by integer zero). - - BasicAclEntry implementations typically - provide convenience methods, such as - isReadAllowed(), to avoid application classes - needing to perform bit masking themselves. The - SimpleAclEntry and - AbstractBasicAclEntry demonstrate and provide much - of this bit masking logic. - - The AclObjectIdentity itself is merely a - marker interface, so you need to provide implementations for your - domain objects. However, the package does include a - NamedEntityObjectIdentity implementation which will - suit many needs. The NamedEntityObjectIdentity - identifies a given domain object instance by the classname of the - instance and the identity of the instance. A - NamedEntityObjectIdentity can be constructed - manually (by calling the constructor and providing the classname and - identity Strings), or by passing in any domain - object that contains a getId() method. - - The actual AclProvider implementation is - named BasicAclProvider. It has adopted a similar - design to that used by the authentication-related - DaoAuthenticationProvder. Specifically, you define - a BasicAclDao against the provider, so different - ACL repository types can be accessed in a pluggable manner. The - BasicAclProvider also supports pluggable cache - providers (with Acegi Security including an implementation that fronts - EH-CACHE). - - The BasicAclDao interface is very simple to - implement: - - public BasicAclEntry[] getAcls(AclObjectIdentity aclObjectIdentity); - - A BasicAclDao implementation needs to - understand the presented AclObjectIdentity and how - it maps to a storage repository, find the relevant records, and create - appropriate BasicAclEntry objects and return - them. - - Acegi Security includes a single BasicAclDao - implementation called JdbcDaoImpl. As implied by - the name, JdbcDaoImpl accesses ACL information from - a JDBC database. There is also an extended version of this DAO, - JdbcExtendedDaoImpl, which provides CRUD operations - on the JDBC database, although we won't discuss these features here. - The default database schema and some sample data will aid in - understanding its function: - - CREATE TABLE acl_object_identity ( - id IDENTITY NOT NULL, - object_identity VARCHAR_IGNORECASE(250) NOT NULL, - parent_object INTEGER, - acl_class VARCHAR_IGNORECASE(250) NOT NULL, - CONSTRAINT unique_object_identity UNIQUE(object_identity), - FOREIGN KEY (parent_object) REFERENCES acl_object_identity(id) -); - -CREATE TABLE acl_permission ( - id IDENTITY NOT NULL, - acl_object_identity INTEGER NOT NULL, - recipient VARCHAR_IGNORECASE(100) NOT NULL, - mask INTEGER NOT NULL, - CONSTRAINT unique_recipient UNIQUE(acl_object_identity, recipient), - FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity(id) -); - -INSERT INTO acl_object_identity VALUES (1, 'corp.DomainObject:1', null, 'org.acegisecurity.acl.basic.SimpleAclEntry'); -INSERT INTO acl_object_identity VALUES (2, 'corp.DomainObject:2', 1, 'org.acegisecurity.acl.basic.SimpleAclEntry'); -INSERT INTO acl_object_identity VALUES (3, 'corp.DomainObject:3', 1, 'org.acegisecurity.acl.basic.SimpleAclEntry'); -INSERT INTO acl_object_identity VALUES (4, 'corp.DomainObject:4', 1, 'org.acegisecurity.acl.basic.SimpleAclEntry'); -INSERT INTO acl_object_identity VALUES (5, 'corp.DomainObject:5', 3, 'org.acegisecurity.acl.basic.SimpleAclEntry'); -INSERT INTO acl_object_identity VALUES (6, 'corp.DomainObject:6', 3, 'org.acegisecurity.acl.basic.SimpleAclEntry'); - -INSERT INTO acl_permission VALUES (null, 1, 'ROLE_SUPERVISOR', 1); -INSERT INTO acl_permission VALUES (null, 2, 'ROLE_SUPERVISOR', 0); -INSERT INTO acl_permission VALUES (null, 2, 'marissa', 2); -INSERT INTO acl_permission VALUES (null, 3, 'scott', 14); -INSERT INTO acl_permission VALUES (null, 6, 'scott', 1); - - As can be seen, database-specific constraints are used - extensively to ensure the integrity of the ACL information. If you - need to use a different database (Hypersonic SQL statements are shown - above), you should try to implement equivalent constraints. The - equivalent Oracle configuration is: - - CREATE TABLE ACL_OBJECT_IDENTITY ( - ID number(19,0) not null, - OBJECT_IDENTITY varchar2(255) NOT NULL, - PARENT_OBJECT number(19,0), - ACL_CLASS varchar2(255) NOT NULL, - primary key (ID) -); -ALTER TABLE ACL_OBJECT_IDENTITY ADD CONTRAINT FK_PARENT_OBJECT foreign key (ID) references ACL_OBJECT_IDENTITY - -CREATE SEQUENCE ACL_OBJECT_IDENTITY_SEQ; - -CREATE OR REPLACE TRIGGER ACL_OBJECT_IDENTITY_ID -BEFORE INSERT ON ACL_OBJECT_IDENTITY -FOR EACH ROW -BEGIN - SELECT ACL_OBJECT_IDENTITY_SEQ.NEXTVAL INTO :new.id FROM dual; -END; - -CREATE TABLE ACL_PERMISSION ( - ID number(19,0) not null, - ACL_OBJECT_IDENTITY number(19,0) NOT NULL, - RECIPIENT varchar2(255) NOT NULL, - MASK number(19,0) NOT NULL, - primary key (ID) -); - -ALTER TABLE ACL_PERMISSION ADD CONTRAINT UNIQUE_ID_RECIPIENT unique (acl_object_identity, recipient); - -CREATE SEQUENCE ACL_PERMISSION_SEQ; - -CREATE OR REPLACE TRIGGER ACL_PERMISSION_ID -BEFORE INSERT ON ACL_PERMISSION -FOR EACH ROW -BEGIN - SELECT ACL_PERMISSION_SEQ.NEXTVAL INTO :new.id FROM dual; -END; - -<bean id="basicAclExtendedDao" class="org.acegisecurity.acl.basic.jdbc.JdbcExtendedDaoImpl"> - <property name="dataSource"> - <ref bean="dataSource"/> - </property> - <property name="objectPropertiesQuery" value="${acegi.objectPropertiesQuery}"/> -</bean> - -<prop key="acegi.objectPropertiesQuery">SELECT CHILD.ID, CHILD.OBJECT_IDENTITY, CHILD.ACL_CLASS, PARENT.OBJECT_IDENTITY as PARENT_OBJECT_IDENTITY FROM acl_object_identity as CHILD LEFT OUTER JOIN acl_object_identity as PARENT ON CHILD.parent_object=PARENT.id WHERE CHILD.object_identity = ?</prop> - - The JdbcDaoImpl will only respond to requests - for NamedEntityObjectIdentitys. It converts such - identities into a single String, comprising - the NamedEntityObjectIdentity.getClassname() + - ":" + - NamedEntityObjectIdentity.getId(). This yields the - type of object_identity values shown above. As - indicated by the sample data, each database row corresponds to a - single BasicAclEntry. As stated earlier and - demonstrated by corp.DomainObject:2 in the above - sample data, each domain object instance will often have multiple - BasicAclEntry[]s. - - As JdbcDaoImpl is required to return concrete - BasicAclEntry classes, it needs to know which - BasicAclEntry implementation it is to create and - populate. This is the role of the acl_class column. - JdbcDaoImpl will create the indicated class and set - its mask, recipient, - aclObjectIdentity and - aclObjectParentIdentity properties. - - As you can probably tell from the sample data, the - parent_object_identity value can either be null or - in the same format as the object_identity. If - non-null, JdbcDaoImpl will create a - NamedEntityObjectIdentity to place inside the - returned BasicAclEntry class. - - Returning to the BasicAclProvider, before it - can poll the BasicAclDao implementation it needs to - convert the domain object instance it was passed into an - AclObjectIdentity. - BasicAclProvider has a protected - AclObjectIdentity obtainIdentity(Object domainInstance) - method that is responsible for this. As a protected method, it enables - subclasses to easily override. The normal implementation checks - whether the passed domain object instance implements the - AclObjectIdentityAware interface, which is merely a - getter for an AclObjectIdentity. If the domain - object does implement this interface, that is the identity returned. - If the domain object does not implement this interface, the method - will attempt to create an AclObjectIdentity by - passing the domain object instance to the constructor of a class - defined by the - BasicAclProvider.getDefaultAclObjectIdentity() - method. By default the defined class is - NamedEntityObjectIdentity, which was described in - more detail above. Therefore, you will need to either (i) provide a - getId() method on your domain objects, (ii) - implement AclObjectIdentityAware on your domain - objects, (iii) provide an alternative - AclObjectIdentity implementation that will accept - your domain object in its constructor, or (iv) override the - obtainIdentity(Object) method. - - Once the AclObjectIdentity of the domain - object instance is determined, the BasicAclProvider - will poll the DAO to obtain its BasicAclEntry[]s. - If any of the entries returned by the DAO indicate there is a parent, - that parent will be polled, and the process will repeat until there is - no further parent. The permissions assigned to a - recipient closest to the domain object instance - will always take priority and override any inherited permissions. From - the sample data above, the following inherited permissions would - apply: - - --- Mask integer 0 = no permissions ---- Mask integer 1 = administer ---- Mask integer 2 = read ---- Mask integer 6 = read and write permissions ---- Mask integer 14 = read and write and create permissions - ---------------------------------------------------------------------- ---- *** INHERITED RIGHTS FOR DIFFERENT INSTANCES AND RECIPIENTS *** ---- INSTANCE RECIPIENT PERMISSION(S) (COMMENT #INSTANCE) ---------------------------------------------------------------------- ---- 1 ROLE_SUPERVISOR Administer ---- 2 ROLE_SUPERVISOR None (overrides parent #1) ---- marissa Read ---- 3 ROLE_SUPERVISOR Administer (from parent #1) ---- scott Read, Write, Create ---- 4 ROLE_SUPERVISOR Administer (from parent #1) ---- 5 ROLE_SUPERVISOR Administer (from parent #3) ---- scott Read, Write, Create (from parent #3) ---- 6 ROLE_SUPERVISOR Administer (from parent #3) ---- scott Administer (overrides parent #3) - - So the above explains how a domain object instance has its - AclObjectIdentity discovered, and the - BasicAclDao will be polled successively until an - array of inherited permissions is constructed for the domain object - instance. The final step is to determine the - BasicAclEntry[]s that are actually applicable to a - given Authentication object. - - As you would recall, the AclManager (and all - delegates, up to and including BasicAclProvider) - provides a method which returns only those - BasicAclEntry[]s applying to a passed - Authentication object. - BasicAclProvider delivers this functionality by - delegating the filtering operation to an - EffectiveAclsResolver implementation. The default - implementation, - GrantedAuthorityEffectiveAclsResolver, will iterate - through the BasicAclEntry[]s and include only those - where the recipient is equal to either the - Authentication's principal or - any of the Authentication's - GrantedAuthority[]s. Please refer to the JavaDocs - for more information. - - - - - - - - Figure 8: ACL Instantiation Approach - - - - The above figure explains the key relationships between objects - in the Basic ACL package. -
-
-
- - - Other Resources - - - In addition to this reference guide, a number of other resources - exist to help you learn how to use Acegi Security. These resources are - discussed in this section. - - - - Sample Applications - - - Contacts - - Included with Acegi Security is a very simple application that - can demonstrate the basic security facilities provided by the system - (and confirm your Container Adapter is properly configured if you're - using one). - - If you build from Subversion, the Contacts sample application - includes three deployable versions: - acegi-security-sample-contacts-filter.war is - configured with the HTTP Session Authentication approach. - Acegi-security-sample-contacts-ca.war - is configured to use a Container Adapter. Finally, - acegi-security-sample-contacts-cas.war is designed - to work with a JA-SIG CAS server. If you're just wanting to see how - the sample application works, please use - acegi-security-sample-contacts-filter.war - as it does not require special configuration of your container. This - is also the artifact included in official release ZIPs. - - To deploy, simply copy the relevant WAR file from Acegi Security - distribution into your container’s webapps - directory. - - After starting your container, check the application can load. - Visit - http://localhost:8080/acegi-security-sample-contacts-filter - (or whichever URL is appropriate for your web container and the WAR - you deployed). A random contact should be displayed. Click "Refresh" - several times and you will see different contacts. The business method - that provides this random contact is not secured. - - Next, click "Debug". You will be prompted to authenticate, and a - series of usernames and passwords are suggested on that page. Simply - authenticate with any of these and view the resulting page. It should - contain a success message similar to the following: - -
- Context on SecurityContextHolder is of type: - org.acegisecurity.context.SecurityContextImpl - - The Context implements SecurityContext. - - Authentication object is of type: - org.acegisecurity.adapters.PrincipalAcegiUserToken - - Authentication object as a String: - org.acegisecurity.adapters.PrincipalAcegiUserToken@e9a7c2: Username: - marissa; Password: [PROTECTED]; Authenticated: true; Granted - Authorities: ROLE_TELLER, ROLE_SUPERVISOR - - Authentication object holds the following granted - authorities: - - ROLE_TELLER (getAuthority(): ROLE_TELLER) - - ROLE_SUPERVISOR (getAuthority(): ROLE_SUPERVISOR) - - SUCCESS! Your [container adapter|web filter] appears to be - properly configured! -
- - If you receive a different message, and deployed - acegi-security-sample-contacts-ca.war, check you - have properly configured your Container Adapter as described elsewhere - in this reference guide. - - Once you successfully receive the above message, return to the - sample application's home page and click "Manage". You can then try - out the application. Notice that only the contacts available to the - currently logged on user are displayed, and only users with - ROLE_SUPERVISOR are granted access to delete their - contacts. Behind the scenes, the - MethodSecurityInterceptor is securing the business - objects. If you're using - acegi-security-sample-contacts-filter.war - or acegi-security-sample-contacts-cas.war, the - FilterSecurityInterceptor is also securing the HTTP - requests. If using either of these WARs, be sure to try visiting - http://localhost:8080/contacts/secure/super, which - will demonstrate access being denied by the - FilterSecurityInterceptor. Note the sample - application enables you to modify the access control lists associated - with different contacts. Be sure to give this a try and understand how - it works by reviewing the sample application's application context XML - files. - - The Contacts sample application also include a - client directory. Inside you will find a small - application that queries the backend business objects using several - web services protocols. This demonstrates how to use Acegi Security - for authentication with Spring remoting protocols. To try this client, - ensure your servlet container is still running the Contacts sample - application, and then execute client marissa koala. - The command-line parameters respectively represent the username to - use, and the password to use. Note that you may need to edit - client.properties to use a different target - URL. - - Please note the sample application's client - does not currently support CAS. You can still give it a try, though, - if you're ambitious: try client _cas_stateless_ - YOUR-SERVICE-TICKET-ID. -
- - - Tutorial Sample - - Whilst the Contacts - Sample is quite advanced in that it illustrates the more - powerful features of domain object access control lists and so on, - sometimes you just want to start with a nice basic example. The - tutorial sample is intended to provide this for you. - - The compiled tutorial is included in the distribution ZIP file, - ready to be deployed into your web container. Authentication is - handled by the DaoAuthenticationProvider, using the - in-memory - UserDetailsService that sources information from - the users.properties file located in the WAR's - /WEB-INF directory. The form-based authentication mechanism is used, - with the commonly-used remember-me - authentication provider used to automatically remember the login using - cookies. - - In terms of authorization, to keep things simple we've - configured the tutorial to only perform some basic web filter - authorization. We've wired two common pre-invocation access decision voters, - being the RoleVoter and - AuthenticatedVoter, such that - ROLE_* configuration attributes and - IS_AUTHENTICATED_* configuration attributes may be - used. Of course, it's extremely easy to add in other providers, with - most users probably starting with some services-layer security using - MethodSecurityInterceptor. - - We recommend you start with the tutorial sample, as the XML is - minimal and easy to follow. All of the needed filters are configured properly, and using - best practise. Most importantly, you can easily this one XML file (and - its corresponding web.xml entries) to your existing - application. Only when this basic integration is achieved do we - suggest you attempt adding in method authorization or domain object - security. - -
- - - Community Support - - - Use JIRA for Issue Tracking - - Acegi Security uses JIRA to manage bug reports and enhancement - requests. If you find a bug, please log a report using JIRA. Do not - log it on the support forum, mailing list or by emailing the project's - developers. Such approaches are ad-hoc and we prefer to manage bugs - using a more formal process. - - If possible, in your JIRA report please provide a JUnit test - that demonstrates any incorrect behaviour. Or, better yet, provide a - patch that corrects the issue. Similarly, enhancements are welcome to - be logged in JIRA, although we only accept commit enhancement requests - if you include corresponding unit tests. This is necessary to ensure - project test coverage is adequately maintained. - - You can access JIRA at . - - - - Becoming Involved - - We welcome you to become involved in Acegi Security project. - There are many ways of contributing, including reading the mailing - list and responding to questions from other people, writing new code, - improving existing code, assisting with documentation, developing - samples or tutorials, or simply making suggestions. - - Please read our project policies web page that is available on - Acegi Security home page. This explains the path to become a - committer, and the administration approaches we use within the - project. - - - - Further Information - - Questions and comments on Acegi Security are welcome. Please use - the Spring Community Forum web site at for all support - issues. Remember to use JIRA for bug reports, as explained above. - Everyone is also welcome to join the Acegisecurity-developer mailing - list and participate in design discussions. It's also a good way of - finding out what's happening with regard to release timing, and the - traffic volume is quite light. Finally, our project home page (where - you can obtain the latest release of the project and convenient links - to Subversion, JIRA, mailing lists, forums etc) is at . - - -
-
\ No newline at end of file diff --git a/doc/docbook/images/ACLSecurity.gif b/doc/docbook/images/ACLSecurity.gif deleted file mode 100644 index 7a0d0aa82345ef28853939032b357a0934c5940e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4041 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 diff --git a/doc/docbook/images/AfterInvocation.gif b/doc/docbook/images/AfterInvocation.gif deleted file mode 100644 index 4a27abd650d9b3456912288217155cb646dceb30..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4672 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 Co>9O6 diff --git a/doc/docbook/images/Authentication.gif b/doc/docbook/images/Authentication.gif deleted file mode 100644 index 2111d2e380459ec67831de101affc01a59297b50..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12955 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℘n5yFvogccF(VEnWz9w*(jqm|BLz|i71CB&QcAJX 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 diff --git a/doc/docbook/images/Context.gif b/doc/docbook/images/Context.gif deleted file mode 100644 index 9d63b197ffdb0c80e3f1d275bae0f7757bd1b748..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4269 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 b&UT4;yoY!*n*zd__Q|n3M=ep1J_!6jzF*>! diff --git a/doc/docbook/images/SecurityInterception.gif b/doc/docbook/images/SecurityInterception.gif deleted file mode 100644 index a9e27c59cb7ba2168405a30527331e898401f3c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5532 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 diff --git a/doc/docbook/images/admons/caution.tif b/doc/docbook/images/admons/caution.tif deleted file mode 100644 index 4a282948c4c7ed53a2cab4132152c9923f7eb363..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1978 zcmebD)MDUaXJBaHTM%HOBF4+!!hOu3BSpZ2m-o=a4UGyOVRGC@78N*Fn1mTgu^*ne z;*L$0(G;HMj}kXtX=zR2W)oug(x;}vd4|pLf`&qbk&JK3goqWpg18tM4sYt>NNQ*5 zJO1L!te8d4X6?)=pC(QSU||)yt{QYgWZzM1M#kk|4=&{>4cy$*l3-xF?uL{AUz_5A z50}pAFgB%?DF*m>GD)-@{{F$i>YOfT;)C)He}4t3vbN+MR?Ki#WjWH`E;J#5fkSah z*CvDRdtCvNOpI%k6$_&6*{?lq*|st4mU-vV>qgQQdBM7KAGv%{?hRM3li^KVy1S9x zik*=G2sju77$g`J84MYm7@`=G8L}CQ8LAmtfUpM)r!auv95`Ic0D)T>AaF0kUWRi( zcnu8iF+kvR1_*r5@Sfp29R6n*g@Y>uM&o~Q#Rt7z11bTqgJPg?F|Y&xk=0NVR1Poz z%ZNF^GJpYGT5JXL8G!j8gs%ZfLk3G=Ndlpt1L^lb3@Tv^fu#V1MQ=Zj+J`d)yn#^y zss&&)AHzQe7O)6V5GchAW=nvWNNgr3n*%7$3}v$d*=$fYGmtIF2r&nwMieRzvPldo p4l+|5%Ki*wOEI#7?fS#Uz#t7}vjA&lTO_>>KsEyq{Q;^60RYt05`+K% diff --git a/doc/docbook/images/admons/draft.png b/doc/docbook/images/admons/draft.png deleted file mode 100644 index 0084708c9b8287c51efa6b40b8d492854191455e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17454 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 diff --git a/doc/docbook/images/admons/home.gif b/doc/docbook/images/admons/home.gif deleted file mode 100644 index 6784f5bb01e0104c60e006a2ed525163a380135c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 321 zcmV-H0lxl6Nk%v~VJHA70KxzO;Nak3U|_JYumAu6&;S7N@bCZt@Bjb+EC2ui04M+` z000C22)f+N_DFSAmXsV{#*oJWIwOJ|OFii&dHVi$1?u8o=2teG> zb~7H4%2JKz`Tcy)XEL^=cAP+G_P7moKVb2g%$4rYhp9PeRzLz zfrD6ufORfRiHeIHgKCh5l6Fj1nwy-RR)UybJ_V$url+TLhynwsuCA(~Rj;(Av5lgv zwwtvDw^OsE0|vwftp&x&!i>OQw#ml^r_#R6Z_dKdq|~Li{txWV+q;;-NCjLKH8RzODs`x)zXFqfx?o2&^85@jF7AWJN0jDQd6 TqQ?;{LW&$ovZP522><{)rIw!r diff --git a/doc/docbook/images/admons/home.png b/doc/docbook/images/admons/home.png deleted file mode 100644 index cbb711de712dcf06597a3a8a3d95f6fefda1f245..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1156 zcmeAS@N?(olHy`uVBq!ia0vp^%0SG|!3-oLGuzY{7?>FXd_r6WdIS`E6g8)48qP6v zn&afP)GK*ya`E2cmc1=K$9krmo3ixW(yjNl9=mt!-1BqS-d}tE{`vdw@Bfd2(GVCG zA@J$l5_e#hU`+CMcVXyYmGuB}CVRR#hE&{I8+eiLumVSprtq8v761QlTpYPgC-&05 zDJ{&8o?4V1EYqU7+)vOI#yLg7ec#$`gxH85}f}H9d0^ z(^GvD(=(H^6-@Mu^ehxCE%gm7^bHIZl8Z8nODY|5D~n4qll4-I^-@X;^7BgclJj#X z?o!+VG)@a_TxNP+Vo52`JVR3xV`HP#G)t4DL{lRpBV!ZeBojj;vlKG}W79NC!#D3= nHUM?;fpi4`tz|GatuQpzHqbT@s&o4Ulwt66^>bP0l+XkK0lack diff --git a/doc/docbook/images/admons/important.gif b/doc/docbook/images/admons/important.gif deleted file mode 100644 index 6795d9a819874ca8b833c4d4993988721489070f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1003 zcmd5)v2xQu5Iutd0|w+k5&Zs3?l2X}aDS zjTF}vbzOHH$Mba8b;e`IbzRT%eBTcOF$gq_YY0gQX<;}D0zVAhF!bZtiem@kQ53ld zc?kJw3X()jQz=b5X{r%YqZCjoWEse^T9yffD1>wGXnD2O6PLX4*vhfx$E#2ysKF~)d4pDz}RBuUaVC4^8)m&+y7^CACN zNWZET0BmraH<<4P+`FFGYnVCKQ9;ZBR3T)qVf|%U7d>simE()pGuDQwHb2TG+MBQ_ zvDDA4Qf1%Pj=rj3vOLN4H;wu(_qSJ$@rtK60JzIpt9fbL=6P}WBLJ%VyrBKnwv9gL z@+koKj|(oEHhf+1r)*HA;C;h{WiuO<>j@AFLq1UdID5A%&u-GCYUTM&`rF#A&P{r^ z_xRIVhqhjHEgv=NdwEBz@%x57)QYSpY=k4uyJx0tows>V2jGshqK7Z@I~q3m5W5c^ zZt#o~c$MEO+~MK7@*>Lh!0mEumT-7-ns3eG+lQO)ySz&7zEB7GF&sm<)jwePAZ~s8 Q_s=i~Dg!i1^#?fn4NukiE&u=k diff --git a/doc/docbook/images/admons/important.png b/doc/docbook/images/admons/important.png deleted file mode 100644 index 12c90f607a1b27ddde0a7d922ae255e8c90e883e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 722 zcmV;@0xkWCP)Gdz_qOoSb{LwMwNgp7=gl$4aErG%}mjHRWNrKOy`y@b8JoTa6ut*xc4t*y1SwY|N)#>U3Z&d%1> z*52OU=jZ3|@9+2b_y7O@tTMkk%M`~Kg@u8&dg_P^_0l3yQb639!jLZt^Lx<-O17UeeJ z-|=!77W(jGx&e#?FOku-gKofoU0$~4M+dhLFueEauP`}l7LV=;lsOdn%WHure=x;k`m0(bF&MU#) z-qv#^n8(MjB|ykioqII#+`g4no-MU=BK|Sahu_3M_-d*=7hq=~t?^}A)G7 zbairN0An*{V`DL9V>K}|HDobmIW;*pIW=W9HaTQ6F*7kTGI9=S@Bjb+07*qoM6N<$ Ef=i}M4FCWD diff --git a/doc/docbook/images/admons/important.tif b/doc/docbook/images/admons/important.tif deleted file mode 100644 index 184de63711510990ab0a8f483c274d2f11596cef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2020 zcmebD)M7AWXJBX$dk|ousK?9JTDdL8Uq@YU@bJG?*jxfpA<|j-!WmZOftnGps z2`M(7+NV;37GB736>XW?tSpqXE>}~nv-Ps%oEtMlIQW-6+n$q%9M;|CK z_#F#ZV$1tJGvEmalTiEz3u}o#Tuh>mHiUOeO7JnuKG`_As3Jnn>nKNe(yJ$T`WW1e~GYvWZ4Wap86IdPu0ZRZU zVEzvR=YI)c=}-+U1EPR<3b=fz29^QIz>)z}8Z2c{1j=VaONynyvH(;CHn0?60O~UY>I?#w0~|oMCXfdzd#ZtD0Rym90=efsxO4)k@&c9v z5Z5Y>mIBlY0dHWCG6FG-=41HBzycNl3Ie5=!E6Z-6N$|PWrOMuW+jIb=LGEI8QAA*>a1B0!;`T|n7uj>pG`jtu{evhJMNxcGSe4+aUA4;zBR~SJyxQRUcWR@_F-^jeWYB);NUiculZ3jmx6N0 zeB+OSXDhy@IoCx0FO{tph>zHm!T!klb*W-Q^N$-zxf}}=>~`{%GD&ps=U<*F$^Pgw z_kzS@O+PsF&r}G^Pim1AepDS}@Ytzl3Ts+UM}N_=nLk9*dAj;P>|etE;is#v!2PUi yKjIc2Q@7UKxAw<}hlktwFXd_r6qS{MX+1QdG|HK%AA z&M|bFA9tAudUsBZ|kvp$Id-JckTVP=kK4t z|Nj2}C>RZap&SB+ixVCKvjk(3x4R2N2dk_Hkkjkw;uunKYwyH|T!$5ST0$SiY~H5U zR{cLbR)lT!-5c|b6rGCX%N?2P<`-xxUu`gZx87&*3!~4wH@%p0)WuYX}UBIC~8cAiK_+plk!-xP|nq~%Rem@g?39waS$dFIAw`2be&`&H`~ zup7N@y!g@N+18CSR#dLnIlgB9pXN>WRz-=n38I0oRnmeW@(a^WRPZVkYb)}kZ6%y pT0bWnsEZGzD*$LMgRyCap{cfkwt-Nc+b5t5gQu&X%Q~loCIEjWXuALa diff --git a/doc/docbook/images/admons/note.gif b/doc/docbook/images/admons/note.gif deleted file mode 100644 index f329d359e55c7ed753170a6f04fbc0cba1e1e565..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 580 zcmZ?wbhEHblwgox_`=Ho1YTZVK|w)LQBlds$=TW2#l^+d)zvL6Ej>LwQ>IK=x^(H* zty}l*-FxiVv2*9nUAuPe-o1OzpFe;9{{8>||AFElBX9%7pDc_F45AD=ASEC>8Cd@% zghGJlBo$966GSzJUe!6ZN$1q35SXB^-zJAkEPj)pXq*a$h_ zXQ+sXsjhEmXhNv37hJ?OaLOg1X|~+1jSyWR(o`3y(c1;Ai!}%$em*Glyc1BwlJ~NK zuZpLThNs9@k1ImH0$Wth2s`>W>73rA(RIXT!4{9MLpCC+wq2hkd_`O*d~)g9;?U*N zC}OI4M1Z6Hl7Y`-pGiWx6O;l)uFCkcxOF@EUU3NwS>oY6#RI6O?U2byr$d1v9)TjN znwNw$j~n?OWwbpf2zH99Zo*Lqk)s;^7gg9U27sNV>(8nyV%m64QG)9cM8x-WNa$(j zzz`MJAQq_8eSmmjy7}|Lu@zf kf(CKug-JSrEM6BktMtGlBGk2ik;bV{KB5sIO^OWG0Fd3m^#A|> diff --git a/doc/docbook/images/admons/note.png b/doc/docbook/images/admons/note.png deleted file mode 100644 index d0c3c645ab9af6318035b026dd86944b9ddc9114..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 490 zcmeAS@N?(olHy`uVBq!ia0vp^5+KY0Bp8m$B&h%?rX+877Y2q^y~;)m42&$EE{-7; zw^Ao5PC9JB<666~wbh%Oo7tJ0_rGWfi({a(qjR96>_P4H$tJl=Pxd^1p6`8M?=jE( z!hchf6<8Mi`NHe6`iia69>!lxe4C2-S>+Wvj;l63k!MNSb9|1+f-i>irDi|a^uLl% z^#-f2#pQ2lC%m~9m9JWJZL3|T8FRX>A78<>cU{Z6XGFG336=OLGkw25|29|RG_k%U z>j|M}Ih2i#-w+9_WSj8)*j_s0*s+gA3;Sh&ja)bx!VF_Sf>*se@&+kCgO zr+R@?&ik*cqgb|1nDsf`Smu_<(#~sYRz=fNIgWLC7l}#=|C@V!^7^u?J-&S9hp(U4 z$p4Zq##20*5QGIHvwJ-nxqBD;h diff --git a/doc/docbook/images/admons/prev.gif b/doc/docbook/images/admons/prev.gif deleted file mode 100644 index 64ca8f3c7c6856d17625615c7845d9adf8b35e6d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1118 zcmZ?wbh9u|RAW$Q_|5jIb=LGEI8QAA*>a1V#C72?E=btEDjqN9qpDd4zl5RF#mYJf^(P5PkwoZW(JQ{ zF_D*4y!wR%9~DOmG#sD7{_&y;#{p%(<{xE#Uw&*>uv^H)Skbd{qJrHLc7}?c9UtQz zYXTT6YHoZvu)pcYrmCD9p$~wJBmbf!%0P@OYB}B?fNF{YnIe9ySJ<~ln9<}1LcYr;@((b@HMtAlPLh^PsKR!G>+|CbXxWHL3#->LwIhe?U cW`4ULC`3qLrpm*X4$b9ricTFB5n!+e06MwKH~;_u diff --git a/doc/docbook/images/admons/prev.png b/doc/docbook/images/admons/prev.png deleted file mode 100644 index cf24654f8a9d6826bf5ee3f6b640d0b34f44d2ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1132 zcmeAS@N?(olHy`uVBq!ia0vp^%0SG|!3-oLGuzY{7?>FXd_r6qS{MX+1QdG|HK%AA z&M|bFA9tAudO|H@7THL=dQiK_Wb?x_ut?D z9|fZ!FvLS(&zmEwfLVeu$=lt9p@UV{1IVfNba4!+xV3fSLB2x#g-7SkiDHi<0%5c709k4@>c%U5PUn6XiNrQ7+$BX-K(BEj>;XDjvwZcIF~ zikDl%a$|T|&B@5M-I14sdv^1r*gkp|z3k=crb$1i`yH45`zBpRc(KYI-u^rPzjiy@ zGH(5%+Qq}Yvm59P=MvY5lHmNblJdl&R0anPWlhiA#Pn3(#PrPMYy}fNBRvZROG|wN z3w;Aah2)~l;*v^-+{)sT%w)aPV!f2og8aM^z2yAdiMtec0FBcE8<&}$msnB?G|wQ- z!aOlC%^=CZB-O|yDbdi(G|ec{Bq=S?EGaqB)I9sbjHy6fd>~x`Kx-L{O)CsdwGFfl UgzDTr0c99GUHx3vIVCg!0Q2->tpET3 diff --git a/doc/docbook/images/admons/tip.gif b/doc/docbook/images/admons/tip.gif deleted file mode 100644 index 823f2b417c797bcc5b5af0d86034bbbe68a9c5d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 598 zcmaKpzfZzI6vwMTVkAa>9EomJF@dB^cAyaw8YzNW>;V&-Ax?~pOgK0Qkwp3j7=?eJ zp(Bd}iDHPQ&cwK|BZjz$_padR<(hoox1W3W-n*l8G9sLBGh57bgCWc1aD#QQmI@nS1Ofyy{@WiyWQ4xz1!{fdcDD5FdB`<y3!k zEzMQ}>2XNH@2x$azJrio4y76u%{aaSQ8iI0-$_v{WV^70wC+frSXf@6n4D`V#?Bj* zZt`izA4lq-+})D%wiNUU4VVF+%2sLK@TMg8DV7ztp%Z(?@L;tQU1CsK&Qwqezj{Cq zSwCP?&P}GNbF_4EK-+twGeQq!I#zP|Y+{WP*FI?V_Kf=>vV0rySc_v6yVepU`O=gc N_rd2$!U|dD;1^e0&sYEe diff --git a/doc/docbook/images/admons/tip.png b/doc/docbook/images/admons/tip.png deleted file mode 100644 index 5c4aab3bb3543191c360387c4af9a3cbaa051345..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 449 zcmeAS@N?(olHy`uVBq!ia0vp^l0YoM0VEi-?r};1DW)WEcNYeRRlUkaK;CUn7srr_ zTcwkB3m#VBagbEhuIO1a$!w|j^feEHv@=+|woj32oF*6|l<3XH$!T}Lao)e6jJhoQ z_vr?OZVprC|7iZ8xaicUR0b&zR-JdP408=+?zC0Rn8IN&QLTWhMIcU0X8P7uUN4WB zR_?a_;&p>ll{>(OzfJ4N{OX={Q&zNgO}j31DC;|ya^r9Fjd348&p+!^cT+^sws+=& zCu*T*mRNK3PE;$BNx$Fa_9(Y=&DoXLMFRd#U31O)<`W^F&-o=xbIqK-c?mr!bmn>! zky6TW;ML~4nXw$T{yra=OteL6G!=B;0=?;6;u=vBoS#-wo>-L1;Gm(b>6x3Dp6Z*J zo|&AjV4`QFXQ5zesc&GRZ(yj9T$EW{Qt6OeSzMBtte0A>mr`1gpI4%noS!>!m*Ngk zP=bxiOwUU!DFvFBnrfM1VQy}0X_lO7WM-b2nq**TZkb|inr2~`WR#dJWc*7VsEZGz hD*$LMgOO>4k%_i}w!yxSoa=!y44$rjF6*2UngF(YpwIvS diff --git a/doc/docbook/images/admons/tip.tif b/doc/docbook/images/admons/tip.tif deleted file mode 100644 index 4a3d8c75fd58190ceae8d6ffa621ecf7e925c3c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 420 zcmebD)M8*_WMF8pe-L1yJdc;H$tf{F-CELXO3;xcp67e?gucfex%0l_j;Y3!bk~Iw z*}inn73j9T)O}-3=fCGcYZHT(zR^l}-s<&G=c&#%w(qtbzQr9{)4X|tE-LgF&v4l4 z)p%aZSR=ZsmwRfU)`umDZ@!1L>ZTZTei3kDV32yV!Q3h+-nMlqyV>lRzWV|5XS|!R zJ9po!|JC=_hMz9Ex3Ove_O<7Ki^+ZG3OW)0HK&YExa~knT17|Dw`}IsahgrSch^-` zbR3#}CTEJE3FpcFHhEeT>m*%ClD6O_#XWHUqAtUxv!lnpXbkP%`INR23xxENF% fWR5tL{SwHQVq^u|^$Ez9hO&PF*|tb}fm{Xvme+K0 diff --git a/doc/docbook/images/admons/toc-blank.png b/doc/docbook/images/admons/toc-blank.png deleted file mode 100644 index 6ffad17a0c7a78deaae58716e8071cc40cb0b8e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 318 zcmeAS@N?(olHy`uVBq!ia0vp^{6Ngf!VDzk7iOmbDT4r?5LY1G0LBeqssYGrXgF}- zKtn^rf1vn(hW}s+NCR0w;4iG^2^42c@^*J&=wOxg0CMC!T^vIyZYBTtzyH6zKuy9A zentg0F+qV0g#~P97#OBpaJrNsxA6f`rE`gEL`iUdT1k0gQ7VIjhO(w-Zen_>Z(@38 za<+nro{^q~f~BRtfrY+-p+a&|W^qZSLvCepNoKNMYO!8QX+eHoiC%Jk?!;Y+JAlS% zfsM;d&r2*R1)7&;o@#7ik&>8{Vv?F>U|?x(ZfKHZYGz`bmXczeoR*Z-Hs=yh7cWRx f0MJ?nL(>XNZ3Ars^Rf>h;}|?${an^LB{Ts5OHX0g diff --git a/doc/docbook/images/admons/toc-minus.png b/doc/docbook/images/admons/toc-minus.png deleted file mode 100644 index abbb020c8e2d6705ebc2f0fc17deed30f2977a46..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 259 zcmeAS@N?(olHy`uVBq!ia0vp^{6Ngf0VEhsJkjh1QcOwS?k)@rt9q4-G!sMP)HD-wQzH`-1CumMgJctv6pLi@6hos# qqtv?{|7HPo@q%;(0Ig*(G_A1IHqbUOFZ%#8j=|H_&t;ucLK6V~f=xvL diff --git a/doc/docbook/images/admons/toc-plus.png b/doc/docbook/images/admons/toc-plus.png deleted file mode 100644 index 941312ce0dab168e0efcc5b572e387259880e541..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 264 zcmeAS@N?(olHy`uVBq!ia0vp^{6Ngf0VEhsJkjh1QcOwS?k)@rt9q49T#T`K7w7|w?rspM=lmg95OfodLFfd9rOi4*hH8wIdOfpPPHA_l1 vPBO4aOiebg{jIb=LGEI8QAA*>a1V#C72?E=bjEDjqN9qpDd4szjmF#mYJf^(P5Pk#A^PL<$Q zI+;RG?K?R>ZZ+XJpnRtJN17PRgOAG`Ypgh#KAaFZVBhwmiI3&M#ti2gFIJ`xI|LdI z)N_AywPiSv9NPY48`Fms0t^T1xjuG&jrgXxZ|i>{CW9aPigr7S6dxV77JO*m^5e&) zo(}&F0j>Y}9vSZmQL;N0Bl*v`gWrf@#t#YRf*HM~)&2b!mjeThEhE5z G!5RR%al9%3 diff --git a/doc/docbook/images/admons/up.png b/doc/docbook/images/admons/up.png deleted file mode 100644 index 07634de26b325b09b6686543e3743ec58426e64b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1111 zcmeAS@N?(olHy`uVBq!ia0vp^%0SG|!3-oLGuzY{7?>FXd_r6qS{MX+1QdG|HK%AA z&M|bF#=*s&OJYO?ftdq@1MW_{{H_c7!85p5(1lc z&#VJx3C1LEcNc~ZR#^`qC(YBvF{I+w)Ct~v2NXD1b6>NwI=-vFd2Ozz_LBUAZ6_V# z0_-2ED|^IRKipvRGe~yg+2{$+0#aW-GMHneR${}Twfy{=Zu8*Wewig#Kj<-8yG4i7iAWgR668V7MElu>!lX!rIZ%r=auLs=jTq` zrMLrVoEF%)%=Em(l2V{~M&{;5#umm#78a?N$;qjPhKZ(zMyW=L7Ktfo#^y-|**sf- lni%*%x&naKG8mgy7@BGuXd4LCxqSjjdAjiitKf)ghIjv$xRfA5@!fkDH{bMrpZER!`M%%z$hqF& zRTo^?=>a_=-~^4}0c5}joCOph4kUmZz-=G{VS5-sP2q6X`MO`-x!!*rW ztyZts8;wS@*(?@mpZ^}uZ$}#tfY(x3o*?Xoo>h`d8|jmC(W5ivVgErE1sEKfo%%8K zZm_%KW2+i;iCOE!&3{olD%O0Ac=Thp(EZgCUC z>m{!ZyCyqrXB4)SL^$CI^0ECR$tT=P*F@;1lfy%=Q(o%DDkk-3k1-hj`YC2`iO!;PB{{!F!o39xr+d_Vw5fMTEwpb-s#9q<5Nzz6gIepyU?Lctpr{ZK zVzWaWPAC)#17S8h%;AIuf(Q_yeIybEqS0s^i1YdJcsv0ln9M{Xkpz;-I_^=P))~D~!!Hvpq{Dl8O{rN@cECkt>#DncX%I(O&3i_YgL-$m$VU zT3cLBLS%M1`o{TBX}S|Tbhc)vk!Yp)%rdDd&my(RPsxl%lU$)tC?(1~WuEwClUQn! n$Q8O{Mxt@ukkcT{K0> diff --git a/doc/docbook/images/admons/warning.tif b/doc/docbook/images/admons/warning.tif deleted file mode 100644 index 7b6611ec7a1980022c11ad6877fedf32f41b3df0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1990 zcmebD)MAieXJBaHR|qhCa3Ybt#fe?OBZVhOke}_5p}~zDOYXJdOmf$P_Zjir-v(f(n1LVCeE22NskqJ)$I5g z8XP9S{LzviJ+sf*L4iXe*;u-Tjq%lq8EgzJ!Hcg+?M+EyWoUYBc3S038aqStx-zY! zDFTdKac@c|p3q>CIvAgpWRM#aTC%3+U_*~obs9PKLA zwdWf7S{m)1m+z3c?Wmx@z`-EEAipvhp!;Kbm?5X2D0kj+rcP|eW7(8DkV2Fki5IhEj=NKUH8UqO41H$KE_?`g-zXRd_Q8-9KfPnz02B(N>pejpX z>SzI`howNaA&_POrkNgK+E@xq2Mpl!zyMB5$ACOgn$iTTxCSKe0kI-51uy_p+j}7S z9f(I$z~Bf0U{v4*qwzmD;)zDC@CHUcBM`%AK8Ak`EMO6Es$gUWvn4>Pkl0L6HV06g z8Omk_ve}?)W*}RT5n>KVjVM$cWRn>L~%oSd9oTwL7T+&nxy zyu7@8e0==;`~m_3f`WoVLPEmA!XhFfqN1W=Vq)Ur;t~=Pl9G~AQc}{=(lRnKva+&r za&q$W@(KzHii(O#N=nMg$|@=KYmvnwpwgT3XuL+B!Nqy1Kf0dV2c$ z`UVCDhK7blMn=ZQ#wI2vrlzK5W@hH*<`xzfmX?-QR#w*5);2aawzjr*c6Rpm_6`mX zj*gB_PEO9w&Mq!4uCA_bZf@@G?j9ZO-;?s%`Gi0t*xzX zZEfxC?HwH*ot>RsU0vPX-90@$y}iACeSQ7?{Szikm^g9bq)C$|Po6ww%9N>7r%szT zZTj@-GiJ<~IdkT$S+i!(o;_#IoVj!7&YL%H{`~n17A#n}aN(jwixw|lykyCerAwDC zTefWZ^5rX5tXR2n<*HSyRoH%*%du|NsArKUo+Uftf%D zloLRCf`MZx!~eg#-8I=+I4mvh{{H^{{!R%71_cjB28W*F|L=~16e_0!iH^d4K?Vk| zb9al`Kw>>fAksk-B*h@W3^J6Vpa?9*ApqhqsDq^%6u@FoDMJacLWtCX7jZxbFc_?2 mWngHK`2KIMH&~K^;fMv$8T+eyk`x>!G+)|V|DTD8!5RQaJghJP diff --git a/doc/docbook/images/callouts/1.png b/doc/docbook/images/callouts/1.png deleted file mode 100644 index 7d473430b7bec514f7de12f5769fe7c5859e8c5d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^JRr;gBp8b2n5}^nQC}X^4DKU-G|w_t}fLBA)Suv#nrW z!^h2QnY_`l!BOq-UXEX{m2up>JTQkX)2m zTvF+fTUlI^nXH#utd~++ke^qgmzgTe~DWM4ffP81J diff --git a/doc/docbook/images/callouts/10.gif b/doc/docbook/images/callouts/10.gif deleted file mode 100644 index fb50b06d150685fbc333906361e32afbf7684993..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 968 zcmV;(12_CfNk%w1VGIBa0QUd@000010RaL60s{jB1Ox;H1qB8M1_uWR2nYxX2?+`c z3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LV0RR91EC2ui01N;O000Q30RR2_$0-K}2ss$t`}gnPyBrWO06>re zLJV*J{^dYWt5yncz0OHVaj#T}cmHbDss&(<}jYB?hWAjdxpF-idd;H(xSYY-?o1HkBC4gkG4 qLFjeQT8tF;{=Lfq000002mqw;_V3@nf0S|{K#+pcy?_4#0suRd diff --git a/doc/docbook/images/callouts/10.png b/doc/docbook/images/callouts/10.png deleted file mode 100644 index 997bbc8246a316e040e0804174ba260e219d7d33..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 361 zcmeAS@N?(olHy`uVBq!ia0vp^JRr;gBp8b2n5}^nQWtZ~+OvdJMW|Y+^UT?O-M{rKJsmzxdayJ{ zDCQA!%%@7Jj$q%-wf8e0_jRx8Dqi$}^?K=?6FriQFLv>>oc^CE+aVHhW3=nZ+fQ4!M=ZC7H>3sl|FJr3LwU zC3?yExf6FO?f@F61vV}-Juk7O6lk8Yg;}bFaZ-|HQc7Azopr01?u8M*si- diff --git a/doc/docbook/images/callouts/11.gif b/doc/docbook/images/callouts/11.gif deleted file mode 100644 index 9f5dba4f8df99fff77747affe9c6c03492ec896b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 244 zcmZ?wbhEHb*_Mn*=~*4EC>&cVUKsi~=%nVHqq z)opEU{r&yZr%#_dckZG^i`K1Mw|VpC9Xoa$IdbIe*|V1}UAley_T$Ho-@JMA;lqc2 z|Neo@1p~#OEDVf5mJWyqvXgP}^2;9)OfJm7I)A)~{gLS`_d;ZPy>0S|_X3{XE z)7O>#600DeuDZ?5tOl@ql94%{~0TwC?8m~C^ZqJRG}m@H-L1 z5L@scq?{XUcxG{OP9jig5ySQaTl#^*93bKF#G<^+ymW>G($Cs~V(bw8rA5i93}62@ zzlJGu&d<$F%`0K}c4pdspcorSSx9C{PAbEScbC)|7#JBmT^vIy=9KoYUDZ+`aP)jU z&ny=ErrK^#Gw!AcR}pdfMERuV^@&0$@(#^6b8c@rn^6RWX3pUb z4*6@PZ+H0#u=rjsXzS?6n6*sBGbHqGTU%mCsH?n#%j;eD^2}qe=iX*J@VQ3BRpz+u z{PX#N(^9X${`$90+;!pWs>o@z_n8G)7Uo7PJz`jrS+)QE@=PWHmc~UIw=WmUe73o7 z>^bR(M752aYoNg~ozu7U7&{(U>{s!;bn#f?ItjL^o`e{*EOQHqO;ccnz9hLK5@2cAyw@AaPFL~Cp#02|E|4xeQteNtB7waMs QVCXP-y85}Sb4q9e0GRUFb^rhX diff --git a/doc/docbook/images/callouts/12.gif b/doc/docbook/images/callouts/12.gif deleted file mode 100644 index a373d0b4f4203dc34d00cfc337fce3c6940ac0a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 244 zcmZ?wbhEHb2m08OKLyy@67BNn1 zV`M$b;Hb*j&z8jCVAzz(*|0d1*}-svnJ2^2O#T7^_7xgl3o~c6fy_O;6lj#|@c@$< P%QAt6&q75}91PX~p`BKN diff --git a/doc/docbook/images/callouts/12.png b/doc/docbook/images/callouts/12.png deleted file mode 100644 index 31daf4e2f25b6712499ee32de9c2e3b050b691ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 617 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1SD^YpWXnZI14-?iy0V%N{XE z)7O>#600De9$%>2LVd81Yeb1-X-P(Y5yQ%LXFPyHJS9LOm(=3qqRfJl%=|nCVNOM5 zpg0#u+&RCXvM4h>ql94%{~0TwC?8m~C^ZqJRG}m@H-L1 z5L@scq?{XUcxG{OP9jig5ySQaTl#^*93bKF#G<^+ymW>G($Cs~V(bw8rA5i93}62@ zzlJGu&d<$F%`0K}c4pdspcorSSx9C{PAbEScbC)|7#JBmT^vIy=Cn>wTzx1(qV@bS z0hYvspf(--lM>otrqbK$7p{3DzJ|+KN8%5ows)AI?zWk_n>jwEHXrTJecpEW_0xL= z?}N`*R`T~d2{AN${y8T#GEn4hUb&52^}Op@TW4{oc)A6)%$5=G}h# z?O{QLj@aRcAIf&y&OiUN=H2gq=_}V|pWfuReDV|{jwXw~>#w)I|9$3x|moMMCb?eciM{nM|`S|hUzkmNgCL#gF zpDYZFK)w!03}hz*YvF=rnZlC|CNImJwM-Kz+OQ~d)-w*#q=p-*7PHz|r?uJeim=Ww zV{C0@=>Ntrnaz(OL9u;eM8lFu#sozHRo??kGr1dh7*7~9Ey|P%1DVSLG^)+=Sc1ij PWtl+3XQ84f4hCxgsBBm& diff --git a/doc/docbook/images/callouts/13.png b/doc/docbook/images/callouts/13.png deleted file mode 100644 index 14021a89c2ed3d4881afea6e3a315bce4f95efce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 623 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1SD^YpWXnZI14-?iy0V%N{XE z)7O>#600Dep5bGK9wD%hYeb1-X-P(Y5yQ%LXFPyHJS9LOm(=3qqRfJl%=|nCVNOM5 zpg0#u+&RCXvM4h>ql94%{~0TwC?8m~C^ZqJRG}m@H-L1 z5L@scq?{XUcxG{OP9jig5ySQaTl#^*93bKF#G<^+ymW>G($Cs~V(bw8rA5i93}62@ zzlJGu&d<$F%`0K}c4pdspcorSSx9C{PAbEScbC)|7#JBmT^vIy=Cn>w>~AWNX^a2R zbkveVY|45D7UnZ&JtjPwvdCCscZp0EA*0()#GOw)UH4-^&)y^E*4%UC)*|J}q_Ss;tN`nd8$>x9$_Xb^O2EpX&@C ZI46EzbLxq-voTO7gQu&X%Q~loCIF_C`w;*D diff --git a/doc/docbook/images/callouts/14.gif b/doc/docbook/images/callouts/14.gif deleted file mode 100644 index 6d6642ee96d73aa5b2efe17277f15c63e15ff643..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 244 zcmZ?wbhEHbgv_2w{G2f{P^+Pw{Jgw{P^$RKag>#K=CIF z10zsK2P6!#lYzA`VOnY=t7jyToEFN;z;JkSYGfEE2V(<6l11b+S?_5KEX!CT+8F(( zvRqlp;LjGuAfVc->c}`bkwHN5baLRK$*JrYWEePfJPT4IRYB%D08MZc1e)(ZEfr|E OB-C)A`C!DsU=08}Mo-uP diff --git a/doc/docbook/images/callouts/14.png b/doc/docbook/images/callouts/14.png deleted file mode 100644 index 64014b75fe2e84d45ed861974c72462727979360..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 411 zcmV;M0c8G(P)!ax*-PXaQ9e~6^e1gu=a6a&KSz}bR`+prYG9ayB$BDjWGfIE;t#wl!+ zR3S(jA%y#i_@eOOedXoc%RQe%L;wH~k+s%ZI~)!<=dD%?4MaplaU9QPGski2q3`>r z(}{j@0a$CLl+)={2vLWml*i-oa5#J}DW$gCZB~Z!(!M#)2St|1_V^0qpmCrBof=Y&NUas@LmfSw=)4B4f;8Fu)(eFsv24 zJzXxBrayquXcR?Ji+1bU# z#kIAy&CSg{Jw1~rPo6n*=86?7wrtt5XV0EPhYnr2a^>dDn-3m5c>DJ4moH!b{rd+p z6b2N3vM?|LIXWN#kev*yg%7sn&Q|rkxh?nhwpdmMhK9|#x2N%XFg5sYwz$1bx0{Xk z_GO0a+gN$Os>~K+Jja&BAYj`ToN;JVE|Y+*Pie-X&AB`WbeJq+xeIcm-9YAoOlVUC XntyRyF3|Aku*lmW!=WgegTWdA>{?yt diff --git a/doc/docbook/images/callouts/15.png b/doc/docbook/images/callouts/15.png deleted file mode 100644 index 0d65765fcf13dcfd87914744dec8bda115e4adf1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 640 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1SD^YpWXnZI14-?iy0V%N{XE z)7O>#600De0j~t#c`vY#Yeb1-X-P(Y5yQ%LXFPyHJS9LOm(=3qqRfJl%=|nCVNOM5 zpg0#u+&RCXvM4h>ql94%{~0TwC?8m~C^ZqJRG}m@H-L1 z5L@scq?{XUcxG{OP9jig5ySQaTl#^*93bKF#G<^+ymW>G($Cs~V(bw8rA5i93}62@ zzlJGu&d<$F%`0K}c4pdspcorSSx9C{PAbEScbC)|7#JBmT^vIy=9Eq_Jl&Ka(%QdX zh{H8O%#_7)Tc@t$mM`p4(Ne7omR*~(>gd8_8AZH{=3ms$Fmzm^yL@_+(#aQQ5>7QW z>3g2fIsH(ugM)!V$x4Rr_+!J_XU%4xbz0aE;^N{m@42Z|@0S@TQ=WbP`TMV5Ok;<| z^Ihv+@6tQ{sciRF9dD7Nr=KobwJJ68zJK$<1Pd9rz%4O)*;}Jzj&~nTGMecz>B%lV zK|`fmIc8mp-h8iSXiGFW=C(L+XH4DRxZQX87^-dLuD>odo6YLT@Sw)dfBEIG)v2@6 zR)%mL7GRj1x-&v&+2q@A%a&h0`Lw7|#(w_!tgT!PoJ|+re`l6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LV0RR91EC2ui01N;O000Q30RR2FM=1vc2st?2`}gnPxflQdqzC~3 zK#X($?!^EQ!rHla#vlNQagPxI0Hv$}2yu@Q004|)006*f4*&q(Y5@Qc0|5X40001p zac>R)001^@s67~R_g00000F&F^=u;$*F7%?ya0Kn*83;>+Y qojZ4K4}ci={+){f00000006`|_wV1odyHZrK#+sdy?_4#0suS0gSs35 diff --git a/doc/docbook/images/callouts/2.png b/doc/docbook/images/callouts/2.png deleted file mode 100644 index 5d09341b2f6d2ea2d1d5dad5d980f14b4b05dfd2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 353 zcmeAS@N?(olHy`uVBq!ia0vp^JRr;gBp8b2n5}^nQxaY7e*=hH)_rZeB4|imU1$R#1`!P>&$poQl;nzm}mD5ZFopaX|GsS%q*{P~< z;WtmO%lhToBL0i}yfkaOt?EN=nkLNGuU`ywhI5H)L`iUdT1k0gQ7VIjhO(w-Zen_> zZ(@38a<+nro{^q~f~BRtfrY+-p+a&|W^qZSLvCepNoKNMYO!8QX+eHoiC%Jk?!;Y+ zJAlS%fsM;d&r2*R1)67JkeZlkYGj#gX_9E3W@4U_nw*@Ln38B@k(iuhnUeN2e6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LV0RR91EC2ui01N;O000Q30RR2FM=1vc2st?2`}gnPxflQtl zK#X($?!^EA!J9R2&L9AYagPxI0CUbEfbee(004|)0000X1po;D)&Kwy0|5X4006W) zXAJ=W001^@tB7y$s_tQG(OF&F^=!026!9PbDL0Kn*83;+;X q-MiNc0e~3y{+&w!00062006`|_wV1odyHZrfDnVyy?_4#0suROfV)2c diff --git a/doc/docbook/images/callouts/3.png b/doc/docbook/images/callouts/3.png deleted file mode 100644 index ef7b70047158970cf4e09f1bab2954d39c2d596b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 350 zcmeAS@N?(olHy`uVBq!ia0vp^JRr;gBp8b2n5}^nQF0kK0(Y1u|9Rc(19XFPiEBhjaDG}zd16s2gM)^$re|(qda7?? zdS-IAf{C7yo`r&?rM`iMzJZ}aa#3b+Nu@(>WpPPnvR-PjUP@^}eqM=Qa(?c_U5Yz^ z#%Y0#%S_KpEGY$=XJL?(l#*ybuErX#^g`ttQfwn6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LV0RR91EC2ui01N;O000Q30RR2_*Gfu?6iQ0{`}gnPJtY7D07wA= zK#p_&{wVRjGG#0000G0|Nj6TFybZ zHwOR!00=Mu2=Q)CihGPO004kM34k&G{{8#+uM_|PF-idd0001hdvgE)0Kn*84gdfE q0Pwa30Du(t{=Lfq00000005-$_V3@ndz@lGKoEn`y?_4#0suSSP`y|H diff --git a/doc/docbook/images/callouts/4.png b/doc/docbook/images/callouts/4.png deleted file mode 100644 index adb8364eb5d21ecdd4086e16110b62ddcb42aa4a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 345 zcmeAS@N?(olHy`uVBq!ia0vp^JRr;gBp8b2n5}^nQ3r>K)tuC)r#2`iJ>Prt42#Ndx#Uc~1)>aw z3jE@Q4|!9Z%lVv}- zc=48cF7H)t`(Ck`^+mtha~Np7bBSw2NpOBzNqJ&XDuaWDvZiNlVtT4?VtQtBwt|VC zk)DNurKP@sg}#BILUK`NaY>~^Ze?*vX0l#tv0h4PL4IC|UUGi!#9fLzfW~Qojmu2W zODrh`nrE42VU(7fm~5G9U~HM3l#*m_WNcxOXkuz6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LV0RR91EC2ui01N;O000Q30RR2_$0-K}2ss$t`}gnPyBr8oqzI7$ zK@4yI{^bCW<{Pv;Y7==^Ow6F-idd5aXYc5Z)*O0Kn*94gdfM qy}MTm0)Q0v{=Lfq00066005-$_V3@nf0S|{KoEn`y?_4#0suQhF}%G1 diff --git a/doc/docbook/images/callouts/5.png b/doc/docbook/images/callouts/5.png deleted file mode 100644 index 4d7eb460021e845981861d77614539314f553993..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 348 zcmeAS@N?(olHy`uVBq!ia0vp^JRr;gBp8b2n5}^nQEX4g z+-vfUhb0A>b04=Im{6XiQd1v%r%>h0$G8U7E1If8OQ!N~xOYY5h0NDT$p9(iZ?Q&e z18-(+l~J8O`)kc}e&uL$eW&>P-#`~Qm$*ih1m~xflqVLYGB{``YkKA;rl!p+yCFkc(+@-h!Xq*<< zxXkpt#FA2=d1VEBsYynrsitN|Y01eJ$;p;U#>wWX2KP5v&I9V=1L+C? fTFYQ)RAFeOZJ=$?lDoSWD8u0C>gTe~DWM4f^}upZ diff --git a/doc/docbook/images/callouts/6.gif b/doc/docbook/images/callouts/6.gif deleted file mode 100644 index d39640707444f5f67b2cd324143c2d6b40d27a40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 968 zcmV;(12_CfNk%w1VGIBa0QUd@000010RaL60s{jB1Ox;H1qB8M1_uWR2nYxX2?+`c z3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LV0RR91EC2ui01N;O000Q30RR2_*Gfu?6iQ0{`}gnPJtY7DU`PP~ zK#p_&{wV<}SN&x`ij1T|-F-iddu;yKe5ciY-0Kn*84gdfs q-MdE!0Du(t{=Lfq00066005-$_V3@ndz^A0KoEn`y?_4#0suR2o4}_4 diff --git a/doc/docbook/images/callouts/6.png b/doc/docbook/images/callouts/6.png deleted file mode 100644 index 0ba694af6c07d947d219b45a629bd32c60a0f5fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 355 zcmeAS@N?(olHy`uVBq!ia0vp^JRr;gBp8b2n5}^nQ*)Bra@SU# zmiz#bR~{$s2si{S(aY|Z}Vd7tb ouUmn-_&~Y>fYve?8dVq?X&Y!8wB+ut16ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LV0RR91EC2ui01N;O000Q30RR2_S4&EY6iQm%`}gnPJt+_{K)?V2 zLXLC){%HZw>fgVA|EvLsajzEu00000z;I3r005M<000000DxM(0001xBL)Bf002n2 z7XttQ00?3L0001hwORlG004kM3jhEBa{QA500000F=_z-0D#dw1ONa40Kn*<5&!^d q)dBzj0Du(t{=E|d00000005*o_wV1of1Gk4K#+pby?_4#0suR4=(v0U diff --git a/doc/docbook/images/callouts/7.png b/doc/docbook/images/callouts/7.png deleted file mode 100644 index 472e96f8ac36862c5645732f2fff19d06ee11a8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 344 zcmeAS@N?(olHy`uVBq!ia0vp^JRr;gBp8b2n5}^nQu%w%U~xZhnMEEs6JbBSw2NpOBzNqJ&XDuaWDvZiNlVtT4?VtQtBwt|VC zk)DNurKP@sg}#BILUK`NaY>~^Ze?*vX0l#tv0h4PL4IC|UUGi!#9fLzfW~Qojmu2W zODrh`nrCEbVQgk$XkwI@Y+{_8nv`N>YGIaQkz#0QY@Te9lBQ<)awbq0A4pdK&{_sV bqY6VKZ3AtCmfYR7Kp6&4S3j3^P66ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LV0RR91EC2ui01N;O000Q30RR2_*Gfu?5K>D0`}gnPJ0$=BKnMW< zK#p_&{s{p9pp-Xjy&wRHajz5r07~vb0B~*&005Mf001E59s~sM)&Kwy0|Nj60BW7{ zW(@%V00=Mu0HEcb6eaK0004kM2><}4dI12?suutNF-iddFy~#05a$R106^)V5C8}$ qoqIu&S`V$cAh@R~F=4@V4jxkzlaQrcFYWK{)(`o5XZnut z=nE4SU2g1ZW%;@@I$>_e3F8a=8WK~|CVXt1DqisQxtIX|`YW_n&?Nh#1gQ}d)$LrYTw(_{nVG)tp2V+#}WG*e^KRLdkoLz7g? qn(IA84Qgo42`r6v<+Hvch>@C7(8A5T-G@yGywn*$#_oy diff --git a/doc/docbook/images/callouts/9.gif b/doc/docbook/images/callouts/9.gif deleted file mode 100644 index bc5c8125b03849986c2df04f65f7406235c700a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 968 zcmV;(12_CfNk%w1VGIBa0QUd@000010RaL60s{jB1Ox;H1qB8M1_uWR2nYxX2?+`c z3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LV0RR91EC2ui01N;O000Q30RR2_*Gfu?5K>y*`}gnPJs|)9K!5-M zK#q6+{wV=~pp~_Ar2qiPajz8s0CT({z;I6s005Mf002;`6#xL%N&x_n0|Nj6d%PjQ zaIY5t00=Mu005!ayL0Di0RVtN2mk;85FkKcjS>I=F-iddAmm;MCI4~&0Kn*84gdgJ q{d>0t0Du(t{=JI<00062006}B_V3@nf0SZCKoEn`y?_4#0suSwcfTJ1 diff --git a/doc/docbook/images/callouts/9.png b/doc/docbook/images/callouts/9.png deleted file mode 100644 index a0676d26cc2ff1de12c4ecdeefb44a0d71bc6bde..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 357 zcmeAS@N?(olHy`uVBq!ia0vp^JRr;gBp8b2n5}^nQNRqa;^5&H%t0&v*|C|wdb9$wI zR@+N9#RIowg@Uqn&z-__Tzhhz!sG|vTxA7?=O|Y?u(d4T{!RM9c7chr6d%1?R=i16 z?@Ic{f32YJFJnVhX)qGzOMplv!L->5yAlT#}irms+fsQd*FoSE84k zpF44v;trs3T43Wc)AJHbN`dAXo0u6Hr<$gkq?lM38ycjV7+5A5Sr{ayr5c%-n;95g pF*H#D>f!_G3IJNmU}#ifXryhRZP1dtyA~+J;OXk;vd$@?2>@J{cB%jX diff --git a/doc/docbook/images/logo.gif b/doc/docbook/images/logo.gif deleted file mode 100644 index f7765dbbb7628caf5f4293688a077d3a021478c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8919 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 diff --git a/doc/docbook/images/logo.psd b/doc/docbook/images/logo.psd deleted file mode 100644 index e02dca01d5c830e6823df9f30de5ce1b3d34cbf6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 149793 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 - - - - - -]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Copyright (c) 2004, 2005, 2006 - - - - , - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -5em - -5em - - - - - - - - - - - - - - - Acegi Security System for Spring - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1 - 0 - 1 - - 1 - - - - - - book toc - - - - 2 - - - - - - - - - - 0 - 0 - 0 - - - 5mm - 10mm - 10mm - - 15mm - 10mm - 0mm - - 18mm - 18mm - - - 0pc - - - - - left - false - - - 11 - 8 - - - 1.4 - - - - - - - 0.8em - - - - - - 17.4cm - - - - 4pt - 4pt - 4pt - 4pt - - - - 0.1pt - 0.1pt - - - - - 1 - - - - - - - - left - bold - - - pt - - - - - - - - - - - - - - - 0.8em - 0.8em - 0.8em - - - pt - - 0.1em - 0.1em - 0.1em - - - 0.6em - 0.6em - 0.6em - - - pt - - 0.1em - 0.1em - 0.1em - - - 0.4em - 0.4em - 0.4em - - - pt - - 0.1em - 0.1em - 0.1em - - - - - bold - - - pt - - false - 0.4em - 0.6em - 0.8em - - - - - - - - wrap - - - - pt - - - - - 1em - 1em - 1em - - - #444444 - solid - 0.1pt - 0.5em - 0.5em - 0.5em - 0.5em - 0.5em - 0.5em - - - - 1 - - #F0F0F0 - - - - - - 0 - 1 - - - 90 - - - - - '1' - &admon_gfx_path; - - - - - - figure after - example before - equation before - table before - procedure before - - - - 1 - - - - 0.8em - 0.8em - 0.8em - 0.1em - 0.1em - 0.1em - - - diff --git a/doc/docbook/styles/xhtml/acegi-chunk.xsl b/doc/docbook/styles/xhtml/acegi-chunk.xsl deleted file mode 100644 index 985254adc3..0000000000 --- a/doc/docbook/styles/xhtml/acegi-chunk.xsl +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - -]> - - - - - - - - '5' - '1' - styles/html/acegi.css - - - 1 - 0 - 1 - 0 - - - - - - book toc - - - - 3 - - - - - 1 - - - - - - - 1 - &callout_gfx_path; - - - 90 - - - - - '1' - &admon_gfx_path; - - - - - - figure after - example before - equation before - table before - procedure before - - - diff --git a/doc/docbook/styles/xhtml/acegi.css b/doc/docbook/styles/xhtml/acegi.css deleted file mode 100644 index 4c06929fc0..0000000000 --- a/doc/docbook/styles/xhtml/acegi.css +++ /dev/null @@ -1,168 +0,0 @@ -A { - color: #003399; -} - -A:active { - color: #003399; -} - -A:visited { - color: #888888; -} - -P, DL, DT, DD, BLOCKQUOTE { - color: #000000; - margin-bottom: 3px; - margin-top: 3px; - padding-top: 0px; - /*border: 1px solid black;*/ -} - -OL, UL, P { - margin-top: 6px; - margin-bottom: 6px; -} - -P, BLOCKQUOTE { - font-size: 90%; -} - -P.releaseinfo { - font-size: 120%; font-weight: bold; - font-family: Arial, helvetica, sans-serif; - padding-top: 10px; -} - -P.pubdate { - font-size: 120%; font-weight: bold; - font-family: Arial, helvetica, sans-serif; -} - -td { - font-size: 80%; -} - - -TD, TH, SPAN { - color: #000000; -} - -BLOCKQUOTE { - margin-right: 0px; -} - -H1, H2, H3, H4, H5, H6 { - color: #000000; - font-weight:500; - margin-top:0px; - padding-top:14px; - font-family: Arial, helvetica, sans-serif; - margin-bottom: 0px; -} - -H2.title { - font-weight:800; - margin-bottom: 8px; -} - -H2.subtitle { - font-weight:800; - margin-bottom: 20px; -} - -H3.author { - color: #000000; - font-weight:500; - margin-top:0px; - padding-top:0px; - font-family: Arial, helvetica, sans-serif; - margin-bottom: 0px; -} - -TABLE { - border-collapse: collapse; - border-spacing:0; - border: 1px thin black; - empty-cells: hide; -} - -TD { - padding: 4pt; -} - -H1 { - font-size: 150%; -} -H2 { - font-size: 110%; -} -H3 { - font-size: 100%; font-weight: bold; -} -H4 { - font-size: 90%; font-weight: bold; -} -H5 { - font-size: 90%; font-style: italic; -} -H6 { - font-size: 100%; font-style: italic; -} - -TT { - font-size: 90%; - font-family: "Courier New", Courier, monospace; - color: #000000; -} - -.navheader, .navfooter { - background-color: #e4eff3; -} - -PRE { - font-size: 90%; - padding: 5px; - border-style: solid; - border-width: 1px; - border-color: #CCCCCC; - background-color: #F4F4F4; -} - -UL, OL, LI { - list-style: disc; -} - -HR { - width: 100%; - height: 1px; - background-color: #CCCCCC; - border-width: 0px; - padding: 0px; - color: #CCCCCC; -} - -.variablelist { - padding-top: 10; - padding-bottom:10; - margin:0; -} - -/*(.itemizedlist, UL { - padding-top: 0; - padding-bottom:0; - margin:0; -}*/ - -.term { - font-weight:bold; -} - -.mediaobject { - padding-top: 30px; - padding-bottom: 30px; -} - -.legalnotice { - font-size: 70%; -} - diff --git a/doc/docbook/styles/xhtml/acegi.xsl b/doc/docbook/styles/xhtml/acegi.xsl deleted file mode 100644 index ab9984b5d9..0000000000 --- a/doc/docbook/styles/xhtml/acegi.xsl +++ /dev/null @@ -1,94 +0,0 @@ - - - - - - - -]> - - - - - - - - styles/html/acegi.css - - - 1 - 0 - 1 - 0 - - - - - - book toc - - - - 3 - - - - - 1 - - - - - - - 1 - &callout_gfx_path; - - - 90 - - - - - '1' - &admon_gfx_path; - - - - - - figure after - example before - equation before - table before - procedure before - - - diff --git a/doc/pom.xml b/doc/pom.xml deleted file mode 100644 index a0a6e0c0e0..0000000000 --- a/doc/pom.xml +++ /dev/null @@ -1,54 +0,0 @@ - - 4.0.0 - - org.acegisecurity - acegi-security-parent - 1.0.5-SNAPSHOT - - acegi-security-doc - Acegi Security System for Spring - Documentation - pom - - - - scm:svn:https://acegisecurity.svn.sourceforge.net/svnroot/acegisecurity/trunk/acegisecurity - scm:svn:https://acegisecurity.svn.sourceforge.net/svnroot/acegisecurity/trunk/acegisecurity - http://acegisecurity.svn.sourceforge.net/viewcvs.cgi/acegisecurity/trunk/acegisecurity/ - - - - - - \ No newline at end of file diff --git a/doc/xdocs/articles.xml b/doc/xdocs/articles.xml deleted file mode 100644 index 43364376c4..0000000000 --- a/doc/xdocs/articles.xml +++ /dev/null @@ -1,153 +0,0 @@ - -External Web Articles covering Acegi Security

Here are some of the external pages mentioning Acegi Security. If you've - found another, please let us know. -

- - -

\ No newline at end of file diff --git a/doc/xdocs/building.xml b/doc/xdocs/building.xml deleted file mode 100644 index 17de53b1c3..0000000000 --- a/doc/xdocs/building.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - Building - -
- - - -

This project uses Maven as project manager - and build tool. We recommend you to install Maven 2.0.5 or greater before trying - the following. Note there are workarounds at the bottom of this page.

To checkout Acegi Security from SVN, see our - CVS Usage page.

- -
- -

Often people reading this document just want to see if Acegi Security will work - for their projects. They want to deploy a sample application, and that's about it - (after all, all the reference documentation can be read online at - http://acegisecurity.org). - In this case, execute:

-
    -
    cd $ACEGI_SECURITY/core (or cd %ACEGI_SECURITY%/core on Windows)
    -
    mvn install
    -
    cd $ACEGI_SECURITY/samples/contacts
    -
    mvn package
    -
    mvn jetty:run
    -
- -

This should build main framework library, build the sample application and run the "contacts" sample application - using the maven jetty plugin. You should then be able to point your browser at - http://localhost:8080/contacts/ to use the application. -

- -
- -
- - - -
\ No newline at end of file diff --git a/doc/xdocs/changes.xml b/doc/xdocs/changes.xml deleted file mode 100644 index fbcd223651..0000000000 --- a/doc/xdocs/changes.xml +++ /dev/null @@ -1,293 +0,0 @@ - - - - - - - Acegi Security changes - - - - All changes are in JIRA at http://opensource2.atlassian.com/projects/spring/secure/ReleaseNote.jspa?projectId=10040 - - - All changes are in JIRA at http://opensource2.atlassian.com/projects/spring/secure/ReleaseNote.jspa?projectId=10040 - - - All changes are in JIRA at http://opensource2.atlassian.com/projects/spring/secure/ReleaseNote.jspa?projectId=10040 - - - All changes are in JIRA at http://opensource2.atlassian.com/projects/spring/secure/ReleaseNote.jspa?projectId=10040 - - - HttpSessionContextIntegrationFilter elegantly handles IOExceptions and ServletExceptions within filter chain (see http://opensource.atlassian.com/projects/spring/browse/SEC-20) - - - HttpSessionContextIntegrationFilter elegantly handles IOExceptions and ServletExceptions within filter chain (see http://opensource.atlassian.com/projects/spring/browse/SEC-20) - - - AbstractIntegrationFilter elegantly handles IOExceptions and ServletExceptions within filter chain (see http://opensource.atlassian.com/projects/spring/browse/SEC-20) - - - Correct location of AuthenticationSimpleHttpInvokerRequestExecutor in clientContext.xml - TokenBasedRememberMeServices changed to use long instead of int for tokenValiditySeconds (SPR-807) - Handle null Authentication.getAuthorities() in AuthorizeTag - PasswordDaoAuthenticationProvider no longer stores String against Authentication.setDetails() - Update commons-codec dependency to 1.3 - AbstractProcessingFilter no longer has setters for failures, it uses the exceptionMappings property - Update to match Spring 1.2-RC2 official JAR dependencies - AuthenticationProcessingFilter now provides an obtainUsername method - Correct PathBasedFilterInvocationDefinitionMap compatibility with Spring 1.2-RC2 - Refactoring to leverage Spring's Assert class and mocks where possible - - - X509 (certificate-based) authentication support - UserDetails now advises locked accounts, with corresponding DaoAuthenticationProvider events and enforcement - ContextHolderAwareRequestWrapper methods return null if user is anonymous - AbstractBasicAclEntry improved compatibility with Hibernate - User now provides a more useful toString() method - Update to match Spring 1.1.5 official JAR dependencies (NB: now using Servlet 2.4 and related JSP/taglib JARs) - SecurityEnforcementFilter caused NullPointerException when anonymous authentication used with BasicProcessingFilterEntryPoint - FilterChainProxy now supports replacement of ServletRequest and ServetResponse by Filter beans - Corrected Authz parsing of whitespace in GrantedAuthoritys - TokenBasedRememberMeServices now respects expired users, expired credentials and disabled users - HttpSessionContextIntegrationFilter now handles HttpSession invalidation without redirection - StringSplitUtils.split() ignored delimiter argument - DigestProcessingFilter now provides userCache getter and setter - Contacts Sample made to work with UserDetails-based Principal - Documentation improvements - Test coverage improvements - - - Added Digest Authentication support (RFC 2617 and RFC 2069) - Added pluggable remember-me services - Added pluggable mechnism to prevent concurrent login sessions - FilterChainProxy added to significantly simplify web.xml configuration of Acegi Security - AuthenticationProcessingFilter now provides hook for extra credentials (eg postcodes) - New WebAuthenticationDetails class now used by processing filters for Authentication.setDetails() - Additional debug-level logging - Improved Tapestry support in AbstractProcessingFilter - Made ConfigAttributeDefinition and ConfigAttribute Serializable - User now accepts blank passwords (null passwords still rejected) - FilterToBeanProxy now searches hierarchical bean factories - User now accepted blank passwords (null passwords still rejected) - ContextHolderAwareRequestWrapper now provides a getUserPrincipal() method - HttpSessionIntegrationFilter no longer creates a HttpSession unnecessarily - FilterSecurityInterceptor now only executes once per request (improves performance with SiteMesh) - JaasAuthenticatinProvider now uses System.property "java.security.auth.login.config" - JaasAuthenticationCallbackHandler Authentication is passed to handle method setAuthentication removed - Added AuthenticationException to the AutenticationEntryPoint.commence method signature - Added AccessDeniedException to the SecurityEncorcementFilter.sendAccessDeniedError method signature - FilterToBeanProxy now addresses lifecycle mismatch (IoC container vs servlet container) issue - Significantly refactor "well-known location model" to authentication processing mechanism and HttpSessionContextIntegrationFilter model - Correct issue with JdbcDaoImpl default SQL query not using consistent case sensitivity - Improve Linux and non-Sun JDK (specifically IBM JDK) compatibility - Log4j now included in generated WAR artifacts (fixes issue with Log4j listener) - Correct NullPointerException in FilterInvocationDefinitionSource implementations - - - Major CVS repository restructure to support Maven and eliminate libraries - Major improvements to Contacts sample application (now demos ACL security) - Added AfterInvocationManager to mutate objects return from invocations - Added BasicAclEntryAfterInvocationProvider to ACL evaluate returned Object - Added BasicAclEntryAfterInvocationCollectionFilteringProvider - Added security propagation during RMI invocations (from sandbox) - Added security propagation for Spring's HTTP invoker - Added BasicAclEntryVoter, which votes based on AclManager permissions - Added AspectJ support (especially useful for instance-level security) - Added MethodDefinitionSourceAdvisor for performance and autoproxying - Added MethodDefinitionMap querying of interfaces defined by secure objects - Added AuthenticationProcessingFilter.setDetails for use by subclasses - Added 403-causing exception to HttpSession via SecurityEnforcementFilter - Added net.sf.acegisecurity.intercept.event package - Added BasicAclExtendedDao interface and JdbcExtendedDaoImpl for ACL CRUD - Added additional remoting protocol demonstrations to Contacts sample - Added AbstractProcessingFilter property to always use defaultTargetUrl - Added ContextHolderAwareRequestWrapper to integrate with getRemoteUser() - Added attempted username to view if processed by AuthenticationProcessingFilter - Added UserDetails account and credentials expiration methods - Added exceptions and events to support new UserDetails methods - Added new exceptions to JBoss container adapter - Improved BasicAclProvider to only respond to specified ACL object requests - Refactored MethodDefinitionSource to work with Method, not MethodInvocation - Refactored AbstractFilterInvocationDefinitionSource to work with URL Strings alone - Refactored AbstractSecurityInterceptor to better support other AOP libraries - Improved performance of JBoss container adapter (see reference docs) - Made DaoAuthenticationProvider detect null in Authentication.principal - Improved JaasAuthenticationProvider startup error detection - Refactored EH-CACHE implementations to use Spring IoC defined caches instead - AbstractProcessingFilter now has various hook methods to assist subclasses - DaoAuthenticationProvider better detects AuthenticationDao interface violations - The User class has a new constructor (the old constructor is deprecated) - Fixed ambiguous column references in JdbcDaoImpl default query - Fixed AbstractProcessingFilter to use removeAttribute (JRun compatibility) - Fixed GrantedAuthorityEffectiveAclResolver support of UserDetails principals - Fixed HttpSessionIntegrationFilter "cannot commit to container" during logoff - Moved MethodSecurityInterceptor to ...intercept.method.aopalliance package - Documentation improvements - Test coverage improvements - - - Resolved to use http://apr.apache.org/versioning.html for future versioning - Added additional DaoAuthenticationProvider event when user not found - Added Authentication.getDetails() to DaoAuthenticationProvider response - Added DaoAuthenticationProvider.hideUserNotFoundExceptions (default=true) - Added PasswordAuthenticationProvider for password-validating DAOs (eg LDAP) - Added FilterToBeanProxy compatibility with ContextLoaderServlet (lazy inits) - Added convenience methods to ConfigAttributeDefinition - Improved sample applications' bean reference notation - Clarified contract for ObjectDefinitionSource.getAttributes(Object) - Extracted removeUserFromCache(String) to UserCache interface - Improved ConfigAttributeEditor so it trims preceding and trailing spaces - Refactored UsernamePasswordAuthenticationToken.getDetails() to Object - Fixed MethodDefinitionAttributes to implement ObjectDefinitionSource change - Fixed EH-CACHE-based caching implementation behaviour when cache exists - Fixed Ant "release" target not including project.properties - Fixed GrantedAuthorityEffectiveAclsResolver if null ACLs provided to method - Documentation improvements - - - Added domain object instance access control list (ACL) packages - Added feature so DaoAuthenticationProvider returns User in Authentication - Added AbstractIntegrationFilter.secureContext property for custom contexts - Added stack trace logging to SecurityEnforcementFilter - Added exception-specific target URLs to AbstractProcessingFilter - Added JdbcDaoImpl hook so subclasses can insert custom granted authorities - Added AuthenticationProvider that wraps JAAS login modules - Added support for EL expressions in the authz tag library - Added failed Authentication object to AuthenticationExceptions - Added signed JARs to all official release builds (see readme.txt) - Added remote client authentication validation package - Added protected sendAccessDeniedError method to SecurityEnforcementFilter - Updated Authentication to be serializable (Weblogic support) - Updated JAR to Spring 1.1 RC 1 - Updated to Clover 1.3 - Updated to HSQLDB version 1.7.2 Release Candidate 6D - Refactored User to net.sf.acegisecurity.UserDetails interface - Refactored CAS package to store UserDetails in CasAuthenticationToken - Improved organisation of DaoAuthenticationProvider to facilitate subclassing - Improved test coverage (now 98.3%) - Improved JDBC-based tests to use in-memory database rather than filesystem - Fixed Linux compatibility issues (directory case sensitivity etc) - Fixed AbstractProcessingFilter to handle servlet spec container differences - Fixed AbstractIntegrationFilter to resolve a Weblogic compatibility issue - Fixed CasAuthenticationToken if proxy granting ticket callback not requested - Fixed EH-CACHE handling on web context refresh - Documentation improvements - - - Added samples/quick-start - Added NullRunAsManager and made default for AbstractSecurityInterceptor - Added event notification (see net.sf.acegisecurity.providers.dao.event) - Updated JAR to Spring 1.0.2 - Updated JAR to Commons Attributes CVS snapshot from Spring 1.0.2 release - Updated GrantedAuthorityImpl to be serializable (JBoss support) - Updated Authentication interface to present extra details for a request - Updated Authentication interface to subclass java.security.Principal - Refactored DaoAuthenticationProvider caching (refer to reference docs) - Improved HttpSessionIntegrationFilter to manage additional attributes - Improved URL encoding during redirects - Fixed issue with hot deploy of EhCacheBasedTicketCache (used with CAS) - Fixed issue with NullPointerExceptions in taglib - Removed DaoAuthenticationToken and session-based caching - Documentation improvements - Upgrade Note: DaoAuthenticationProvider no longer has a "key" property - - - Added single sign on support via Yale Central Authentication Service (CAS) - Added full support for HTTP Basic Authentication - Added caching for DaoAuthenticationProvider successful authentications - Added Burlap and Hessian remoting to Contacts sample application - Added pluggable password encoders including plaintext, SHA and MD5 - Added pluggable salt sources to enhance security of hashed passwords - Added FilterToBeanProxy to obtain filters from Spring application context - Added support for prepending strings to roles created by JdbcDaoImpl - Added support for user definition of SQL statements used by JdbcDaoImpl - Added definable prefixes to avoid expectation of "ROLE_" GrantedAuthoritys - Added pluggable AuthenticationEntryPoints to SecurityEnforcementFilter - Added Apache Ant path syntax support to SecurityEnforcementFilter - Added filter to automate web channel requirements (eg HTTPS redirection) - Updated JAR to Spring 1.0.1 - Updated several classes to use absolute (not relative) redirection URLs - Refactored filters to use Spring application context lifecycle support - Improved constructor detection of nulls in User and other key objects - Fixed FilterInvocation.getRequestUrl() to also include getPathInfo() - Fixed Contacts sample application tags - Established acegisecurity-developer mailing list - Documentation improvements - - - Added HTTP session authentication as an alternative to container adapters - Added HTTP request security interceptor (offers considerable flexibility) - Added security taglib - Added Clover test coverage instrumentation (currently 97.2%) - Added support for Catalina (Tomcat) 4.1.30 to in-container integration tests - Added HTML test and summary reporting to in-container integration tests - Updated JARs to Spring Framework release 1.0, with associated AOP changes - Updated to Apache License version 2.0 - Updated copyright with permission of past contributors - Refactored unit tests to use mock objects and focus on a single class each - Refactored many classes to enable insertion of mock objects during testing - Refactored core classes to ease support of new secure object types - Changed package layout to better describe the role of contained items - Changed the extractor to extract additional classes from JBoss and Catalina - Changed Jetty container adapter configuration (see reference documentation) - Improved AutoIntegrationFilter handling of deployments without JBoss JARs - Fixed case handling support in data access object authentication provider - Documentation improvements - - - Added "in container" unit test system for container adapters and sample app - Added library extractor tool to reduce the "with deps" ZIP release sizes - Added unit test to the attributes sample - Added Jalopy source formatting - Modified all files to use net.sf.acegisecurity namespace - Renamed springsecurity.xml to acegisecurity.xml for consistency - Reduced length of ZIP and JAR filenames - Clarified licenses and sources for all included libraries - Updated documentation to reflect new file and package names - Setup Sourceforge.net project and added to CVS etc - - - Added Commons Attributes support and sample (thanks to Cameron Braid) - Added JBoss container adapter - Added Resin container adapter - Added JDBC DAO authentication provider - Added several filter implementations for container adapter integration - Added SecurityInterceptor startup time validation of ConfigAttributes - Added more unit tests - Refactored ConfigAttribute to interface and added concrete implementation - Enhanced diagnostics information provided by sample application debug.jsp - Modified sample application for wider container portability (Resin, JBoss) - Fixed switch block in voting decision manager implementations - Removed Spring MVC interceptor for container adapter integration - Documentation improvements - - - Initial public release - - - diff --git a/doc/xdocs/cvs-usage.xml b/doc/xdocs/cvs-usage.xml deleted file mode 100644 index daf0a9fef5..0000000000 --- a/doc/xdocs/cvs-usage.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - Subversion Usage - - -
- -

- You can browse the source tree directly via - - http://acegisecurity.svn.sourceforge.net/viewvc/acegisecurity/ - -

-
- -

- The code can be checked out anonymously with the following command: -

-

- svn co http://acegisecurity.svn.sourceforge.net/svnroot/acegisecurity/spring-security/trunk/ -

- -
- -

If you'd prefer not to use subversion directly, please see our - downloads page - for nightly snapshots. -

-
-
- -
\ No newline at end of file diff --git a/doc/xdocs/dbinit.txt b/doc/xdocs/dbinit.txt deleted file mode 100644 index 0746d875af..0000000000 --- a/doc/xdocs/dbinit.txt +++ /dev/null @@ -1,92 +0,0 @@ ---- $Id$ - ---- Sample Hypersonic SQL compatible schema and data ---- ---- All Acegi Security JDBC DAOs can be customised to use a different schema. ---- In addition, the Acegi Security JDBC DAOs do not even need to be used ---- with Acegi Security, and an entirely customised persistence strategy ---- can be employed via standard interfaces (eg in-memory, Hibernate etc). - -SET IGNORECASE TRUE; - -CREATE TABLE users ( - username VARCHAR(50) NOT NULL PRIMARY KEY, - password VARCHAR(50) NOT NULL, - enabled BIT NOT NULL -); - -CREATE TABLE authorities ( - username VARCHAR(50) NOT NULL, - authority VARCHAR(50) NOT NULL -); -CREATE UNIQUE INDEX ix_auth_username ON authorities ( username, authority ); - -ALTER TABLE authorities ADD CONSTRAINT fk_authorities_users foreign key (username) REFERENCES users(username); - -INSERT INTO users VALUES ('marissa', 'koala', true); -INSERT INTO users VALUES ('dianne', 'emu', true); -INSERT INTO users VALUES ('scott', 'wombat', true); -INSERT INTO users VALUES ('peter', 'opal', false); - -INSERT INTO authorities VALUES ('marissa', 'ROLE_TELLER'); -INSERT INTO authorities VALUES ('marissa', 'ROLE_SUPERVISOR'); -INSERT INTO authorities VALUES ('dianne', 'ROLE_TELLER'); -INSERT INTO authorities VALUES ('scott', 'ROLE_TELLER'); -INSERT INTO authorities VALUES ('peter', 'ROLE_TELLER'); - ---- Indexes auto created in HSQLDB for primary keys and unique columns - -CREATE TABLE acl_object_identity ( - id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY, - object_identity VARCHAR_IGNORECASE(250) NOT NULL, - parent_object BIGINT, - acl_class VARCHAR_IGNORECASE(250) NOT NULL, - CONSTRAINT unique_object_identity UNIQUE(object_identity), - FOREIGN KEY (parent_object) REFERENCES acl_object_identity(id) -); - -CREATE TABLE acl_permission ( - id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY, - acl_object_identity BIGINT NOT NULL, - recipient VARCHAR_IGNORECASE(100) NOT NULL, - mask INTEGER NOT NULL, - CONSTRAINT unique_recipient UNIQUE(acl_object_identity, recipient), - FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity(id) -); - ---- Mask integer 0 = no permissions ---- Mask integer 1 = administer ---- Mask integer 2 = read ---- Mask integer 6 = read and write permissions ---- Mask integer 14 = read and write and create permissions - ---------------------------------------------------------------------- ---- *** INHERITED RIGHTS FOR DIFFERENT INSTANCES AND RECIPIENTS *** ---- INSTANCE RECIPIENT PERMISSION(S) (COMMENT #INSTANCE) ---------------------------------------------------------------------- ---- 1 ROLE_SUPERVISOR Administer ---- 2 ROLE_SUPERVISOR None (overrides parent #1) ---- marissa Read ---- 3 ROLE_SUPERVISOR Administer (from parent #1) ---- scott Read, Write, Create ---- 4 ROLE_SUPERVISOR Administer (from parent #1) ---- 5 ROLE_SUPERVISOR Administer (from parent #3) ---- scott Read, Write, Create (from parent #3) ---- 6 ROLE_SUPERVISOR Administer (from parent #3) ---- scott Administer (overrides parent #3) ---------------------------------------------------------------------- - -INSERT INTO acl_object_identity VALUES (1, 'org.acegisecurity.acl.DomainObject:1', null, 'org.acegisecurity.acl.basic.SimpleAclEntry'); -INSERT INTO acl_object_identity VALUES (2, 'org.acegisecurity.acl.DomainObject:2', 1, 'org.acegisecurity.acl.basic.SimpleAclEntry'); -INSERT INTO acl_object_identity VALUES (3, 'org.acegisecurity.acl.DomainObject:3', 1, 'org.acegisecurity.acl.basic.SimpleAclEntry'); -INSERT INTO acl_object_identity VALUES (4, 'org.acegisecurity.acl.DomainObject:4', 1, 'org.acegisecurity.acl.basic.SimpleAclEntry'); -INSERT INTO acl_object_identity VALUES (5, 'org.acegisecurity.acl.DomainObject:5', 3, 'org.acegisecurity.acl.basic.SimpleAclEntry'); -INSERT INTO acl_object_identity VALUES (6, 'org.acegisecurity.acl.DomainObject:6', 3, 'org.acegisecurity.acl.basic.SimpleAclEntry'); - -INSERT INTO acl_permission VALUES (null, 1, 'ROLE_SUPERVISOR', 1); -INSERT INTO acl_permission VALUES (null, 2, 'ROLE_SUPERVISOR', 0); -INSERT INTO acl_permission VALUES (null, 2, 'marissa', 2); -INSERT INTO acl_permission VALUES (null, 3, 'scott', 14); -INSERT INTO acl_permission VALUES (null, 6, 'scott', 1); - - diff --git a/doc/xdocs/downloads.xml b/doc/xdocs/downloads.xml deleted file mode 100644 index f70cd45ea2..0000000000 --- a/doc/xdocs/downloads.xml +++ /dev/null @@ -1,28 +0,0 @@ - -Acegi Security Downloads

If you wish to try out this project, you are probably looking for the - acegi-security-xx.zip file, which contains all of the officially - released JARs, a copy of all documentation, and two WAR artifacts. The two WAR artifacts - are from the Contacts Sample and the Tutorial Sample application. The Tutorial Sample - consists of a "bare bones" configuration that will get you up and running quickly, whereas - the Contacts Sample illustrates more advanced features.

Please note that in order to reduce download size, we only include in the - release ZIP one of the WAR artifacts produced by the Contacts Sample application. - The WAR artifact we include is suitable for standalone deployment (specifically, it - does not require a CAS server, container adapter, X509 or LDAP setup). The official release ZIP - therefore probably contains what you need, especially if you're initially - evaluating the project. If you wish to deploy the other WAR artifacts produced by - the Contacts Sample application (ie those that target CAS, container adapters, X509 or LDAP usage), - you will need to build Acegi Security from source. - -

The acegi-security-xx-src.zip is intended for use with IDEs. It does not contain the - files needed to compile Acegi Security. It also does not contain the sources to the - sample applications. If you need any of these files, please download from SVN.

The official release ZIP files are available from the - Sourceforge File Release System.

The Acegi Security JARs are also available via the - iBiblio Maven Repository.

Detailed instructions on downloading from CVS and building from source - are provided on the Building with Maven - page.

- If you don't wish to access SVN directly, we provide - nightly SVN exports for your convenience. - There is also an automated build which uploads bundle of Acegi Security jar files to the same location. - Both binary and source archives have the date of the build and the SVN revision number appended to the filename, - so you can match them up easily. -

\ No newline at end of file diff --git a/doc/xdocs/faq.xml b/doc/xdocs/faq.xml deleted file mode 100644 index 0133af08a6..0000000000 --- a/doc/xdocs/faq.xml +++ /dev/null @@ -1,207 +0,0 @@ - -Frequently Asked Questions (FAQ) on Acegi Security

Acegi Security is an open source project that provides comprehensive authentication - and authorisation services for enterprise applications based on - The Spring Framework. - Acegi Security can authenticate using a variety of pluggable providers, and - can authorise both web requests and method invocations. - Acegi Security provides an integrated security approach across - these various targets, and also offers access control list (ACL) capabilities to - enable individual domain object instances to be secured. At an implementation - level, Acegi Security is managed through Spring's inversion of control and - lifecycle services, and actually enforces security using interception through - servlet Filters and Java AOP frameworks. In terms of AOP framework support, Acegi - Security currently supports AOP Alliance (which is what the - Spring IoC container uses internally) and AspectJ, although additional frameworks - can be easily supported.

Let's assume you're developing an enterprise application based on Spring. - There are four security concerns you typically need to address: authentication, - web request security, service layer security (ie your methods that implement - business logic), and domain object instance security (ie different domain objects - have different permissions). With these typical requirements in mind: -

    -
  1. Authentication: The servlet specification provides an approach - to authentication. However, you will need to configure the container - to perform authentication which typically requires editing of - container-specific "realm" settings. This makes a non-portable - configuration, and if you need to write an actual Java class to implement - the container's authentication interface, it becomes even more non-portable. - With Acegi Security you achieve complete portability - right down to the - WAR level. Also, Acegi Security offers a choice of production-proven - authentication providers and mechanisms, meaning you can switch your - authentication approaches at deployment time. This is particularly - valuable for software vendors writing products that need to work in - an unknown target environment.



  2. -
  3. Web request security: The servlet specification provides an - approach to secure your request URIs. However, these URIs can only be - expressed in the servlet specification's own limited URI path format. - Acegi Security provides a far more comprehensive approach. For instance, - you can use Ant paths or regular expressions, you can consider parts of the - URI other than simply the requested page (eg you can consider HTTP GET - parameters), and you can implement your own runtime source of configuration - data. This means your web request security can be dynamically changed during - the actual execution of your webapp.



  4. -
  5. Service layer and domain object security: The absence of support - in the servlet specification for services layer security or domain object - instance security represent serious limitations for multi-tiered - applications. Typically developers either ignore these requirements, or - implement security logic within their MVC controller code (or even worse, - inside the views). There are serious disadvantages with this approach:



    -
      -
    1. Separation of concerns: Authorization is a - crosscutting concern and should be implemented as such. - MVC controllers or views implementing authorization code - makes it more difficult to test both the controller and - authorization logic, more difficult to debug, and will - often lead to code duplication.
    2. -
    3. Support for rich clients and web services: If an - additional client type must ultimately be supported, any - authorization code embedded within the web layer is - non-reusable. It should be considered that Spring remoting - exporters only export service layer beans (not MVC - controllers). As such authorization logic needs to be - located in the services layer to support a multitude of - client types.
    4. -
    5. Layering issues: An MVC controller or view is simply - the incorrect architectural layer to implement authorization - decisions concerning services layer methods or domain object - instances. Whilst the Principal may be passed to the services - layer to enable it to make the authorization decision, doing - so would introduce an additional argument on every services - layer method. A more elegant approach is to use a ThreadLocal - to hold the Principal, although this would likely increase - development time to a point where it would become more - economical (on a cost-benefit basis) to simply use a dedicated - security framework.
    6. -
    7. Authorisation code quality: It is often said of web - frameworks that they "make it easier to do the right things, - and harder to do the wrong things". Security frameworks are - the same, because they are designed in an abstract manner for - a wide range of purposes. Writing your own authorization code - from scratch does not provide the "design check" a framework - would offer, and in-house authorization code will typically - lack the improvements that emerge from widespread deployment, - peer review and new versions. -
    -
  6. -
- For simple applications, servlet specification security may just be enough. - Although when considered within the context of web container portability, - configuration requirements, limited web request security flexibility, and - non-existent services layer and domain object instance security, it becomes - clear why developers often look to alternative solutions. -

Ah-see-gee. Said quickly, without emphasis on any part. - Acegi isn't an acronym, name of a Greek God or anything similarly - impressive - it's just letters #1, #3, #5, #7 and #9 of the alphabet.

It's official name is Acegi Security System for Spring, - although we're happy for it to be abbreviated to - Acegi Security. Please don't just call it Acegi, though, - as that gets confused with the name of the company that maintains Acegi - Security.

80% of support questions are because people have not defined - the necessary filters in web.xml, or the filters are being - mapped in the incorrect order. Check the - Reference Guide, which - has a specific section on filter ordering.

The next most common source of problems stem from custom - AuthenticationDao implementations that simply don't properly - implement the interface contract. For example, they return null instead - of the user not found exception, or fail to add in the - GrantedAuthority[]s. Whilst DaoAuthenticationProvider - does its best to check the AuthenticationDao returns a valid - UserDetails, we suggest you write the - UserDetails object to the log and check it looks correct.

A common user problem with infinite loop and redirecting to the login page - is caused by accidently configuring the login page as a "secured" resource. - Generally make sure you mark your login page as requiring ROLE_ANONYMOUS. -

If you are securing web resources and they dont seem to be matched in the URL patterns, - check the objectDefinitionSource in the FilterSecurityInterceptor. - If you are using the CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON setting, - then the URL patterns configured MUST be in lowercase. -

- For example, making a request ending in /someAction.do will need - to be configured as: /someaction.do (Note the case). -

-<property name="objectDefinitionSource">
-  <value>
-    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
-    PATTERN_TYPE_APACHE_ANT
-    /index.jsp=ROLE_ANONYMOUS,ROLE_USER
-    /someaction.do=ROLE_USER     			    
-  <value>
-</property>     
-
- -

A common user requirement is to disable / lock an account after a number of failed login attempts. - Acegi itself does not provide anything "out of the box", however in your application you can implement - and register an org.springframework.context.ApplicationListener. Inside your application - event listener you can then check for an instanceof the particular AuthenticationFailureEvent - and then call your application user management interface to update the user details. -

- For example: -

-     public void onApplicationEvent(ApplicationEvent event) {
-     
-       // check failed event
-       if(event instanceof AuthenticationFailurePasswordEvent){
-          // call user management interface to increment failed login attempts, etc.
-          . . .
-       }  
-     }
-     
- -

There are three things you must do to make a user password change take affect: -

    -
  • Change the password using your authentication DAO
  • -
  • Remove the user from the User Cache (i.e. if you have a cache configured)
  • -
  • Update the SecurityContextHolder to include the new Authentication object and password
  • -
- -

The most important things to post with any support requests on the - Spring Forums are your - web.xml, applicationContext.xml (or whichever - XML loads the security-related beans) as well as any custom - AuthenticationDao you might be using. For really odd problems, - also switch on debug-level logging and include the resulting log.

Acegi Security uses Commons Logging, just as Spring does. So you use the - same approach as you'd use for Spring. Most people output to Log4J, so - the following log4j.properties would work:

- log4j.rootCategory=WARN, stdout - - log4j.appender.stdout=org.apache.log4j.ConsoleAppender - log4j.appender.stdout.layout=org.apache.log4j.PatternLayout - log4j.appender.stdout.layout.ConversionPattern=%d %p %c - %m%n - - log4j.category.net.sf.acegisecurity=DEBUG - -

In most cases write an AuthenticationDao which returns - a subclass of User. Alternatively, write your own - UserDetails implementation from scratch and return that.

Acegi Security targets enterprise applications, which are typically - multi-user, data-oriented applications that are important to - the core business. Acegi Security was designed to provide a portable and effective - security framework for this target application type. It was not designed for securing - limited privilege runtime environments, such as web browser applets.

We did consider JAAS when designing Acegi Security, but it simply - wasn't suitable for our purpose. We needed to avoid complex JRE configurations, - we needed container portability, and we wanted maximum leveraging of the Spring IoC - container. Particularly as limited privilege runtime environments were not - an actual requirement, this lead to the natural design of Acegi Security as - it exists today.

Acegi Security already provides some JAAS integration. It can today authenticate - via delegation to a JAAS login module. This means it offers the same level of JAAS - integration as many web containers. Indeed the container adapter model supported by - Acegi Security allows Acegi Security and container-managed security to happily - co-exist and benefit from each other. Any debate about Acegi Security and JAAS - should therefore centre on the authorisation issue. An evaluation of major - containers and security frameworks would reveal that Acegi Security is by no - means unusual in not using JAAS for authorisation.

There are many examples of open source applications being preferred to - official standards. A few that come to mind in the Java community include - using Spring managed POJOs (rather than EJBs), Hibernate (instead of entity beans), - Log4J (instead of JDK logging), Tapestry (instead of JSF), and Velocity/FreeMarker - (instead of JSP). It's important to recognise that many open source projects do - develop into de facto standards, and in doing so play a legitimate and beneficial - role in professional software development.

Yes. If you've written something and it works well, please feel free to share it. - Simply email the contribution to the - acegisecurity-developers list. If you haven't yet - written the contribution, we encourage you to send your thoughts to the same - list so that you can receive some initial design feedback.

For a contribution to be used, it must have appropriate unit test coverage and - detailed JavaDocs. It will ideally have some comments for the Reference Guide - as well (this can be sent in word processor or HTML format if desired). This - helps ensure the contribution maintains the same quality as the remainder of - the project.

We also welcome documentation improvements, unit tests, illustrations, - people supporting the user community (especially on the forums), design ideas, - articles, blog entries, presentations and alike. If you're looking for something - to do, you can always email the - acegisecurity-developers list and we'll be - pleased to suggest something. :-)

\ No newline at end of file diff --git a/doc/xdocs/index.xml b/doc/xdocs/index.xml deleted file mode 100644 index 866ac97a20..0000000000 --- a/doc/xdocs/index.xml +++ /dev/null @@ -1,176 +0,0 @@ - -Acegi Security System for Spring
What is Acegi Security?


- Acegi Security is a powerful, flexible security solution for enterprise software, - with a particular emphasis on applications that use - Spring. Using Acegi Security provides your - applications with comprehensive authentication, authorization, instance-based access control, - channel security and human user detection capabilities. -



Key Features


    -
  • Stable and mature. Acegi Security 1.0.0 was released in May 2006 after - more than two and a half years of use in large production software projects, 70,000+ downloads - and hundreds of community contributions. - In terms of release numbering, we also use the Apache APR Project - Versioning Guidelines so that you can easily identify release - compatibility.



    -
  • Well documented: All APIs are fully documented using - JavaDoc, - with almost 100 pages of - Reference Guide documentation providing an easy-to-follow - introduction. Even more documentation is provided on this web site, as - shown in the left hand navigation sidebar.



    -
  • Fast results: View our suggested steps - for the fastest way to develop complex, security-compliant applications.



    -
  • Enterprise-wide single sign on: Using JA-SIG's open - source Central Authentication - Service (CAS), the Acegi Security can participate - in an enterprise-wide single sign on environment. You no longer need - every web application to have its own authentication database. Nor are - you restricted to single sign on across a single web container. Advanced - single sign on features like proxy support and forced refresh of logins - are supported by both CAS and Acegi Security.



    -
  • Reuses your Spring expertise: We use Spring application - contexts for all configuration, which should help Spring developers get - up-to-speed nice and quickly.



    -
  • Domain object instance security: In many applications it's - desirable to define Access Control Lists (ACLs) for individual domain - object instances. We provide a comprehensive ACL package with features - including integer bit masking, permission inheritence (including - blocking), a JDBC-backed ACL repository, caching and a pluggable, - interface-driven design.



    -
  • Non-intrusive setup: The entire security system can operate - within a single web application using the provided filters. There is no - need to make special changes or deploy libraries to your Servlet or EJB - container.



    -
  • Full (but optional) container integration: The credential - collection and authorization capabilities of your Servlet or EJB - container can be fully utilised via included "container adapters". We - currently support Catalina (Tomcat), Jetty, JBoss and Resin, with - additional containers easily added.



    -
  • Keeps your objects free of security code: Many applications - need to secure data at the bean level based on any combination of - parameters (user, time of day, authorities held, method being invoked, - parameter on method being invoked....). This package gives you this - flexibility without adding security code to your Spring business - objects.



    -
  • After invocation security: Acegi Security can not only protect - methods from being invoked in the first place, but it can also - deal with the objects returned from the methods. Included implementations - of after invocation security can throw an exception or mutate the returned - object based on ACLs.



    -
  • Secures your HTTP requests as well: In addition to securing - your beans, the project also secures your HTTP requests. No longer is it - necessary to rely on web.xml security constraints. Best of all, your - HTTP requests can now be secured by your choice of regular expressions - or Apache Ant paths, along with pluggable authentication, authorization - and run-as replacement managers.



    -
  • Channel security: Acegi Security can - automatically redirect requests across an appropriate transport channel. - Whilst flexible enough to support any of your "channel" requirements (eg - the remote user is a human, not a robot), a common channel security - feature is to ensure your secure pages will only be available over - HTTPS, and your public pages only over HTTP. Acegi Security also - supports unusual port combinations (including if accessed via an - intermediate server like Apache) and pluggable transport decision - managers.



    -
  • Supports HTTP BASIC authentication: Perfect for remoting - protocols or those web applications that prefer a simple browser pop-up - (rather than a form login), Acegi Security can directly process HTTP - BASIC authentication requests as per RFC 1945.



    -
  • Supports HTTP Digest authentication: For greater security than - offered by BASIC authentcation, Acegi Security also supports Digest Authentication - (which never sends the user's password across the wire). Digest Authentication - is widely supported by modern browsers. Acegi Security's implementation complies - with both RFC 2617 and RFC 2069.



    -
  • Computer Associates Siteminder support: Authentication can be - delegated through to CA's Siteminder solution, which is common in large - corporate environments.



    -
  • X509 (Certificate) support: Acegi Security can easily read - client-side X509 certificates for authenticating users.



    -
  • LDAP Support: Do you have an LDAP directory? Acegi Security can - happily authenticate against it.



    -
  • Tag library support: Your JSP files can use our taglib - to ensure that protected content like links and messages are only - displayed to users holding the appropriate granted authorities. The taglib - also fully integrates with Acegi Security's ACL services, and - obtaining extra information about the logged-in principal.



    -
  • Configuration via IoC XML, Commons Attributes, or JDK 5 Annotations: You - select the method used to configure your security environment. The - project supports configuration via Spring application contexts, as well - as Jakarta Commons Attributes and Java 5's annotations feature. Some users - (such as those building content management systems) pull configuration data - from a database, which exemplifies Acegi Security's flexible configuration - metadata system.



    -
  • Various authentication backends: We include the ability to - retrieve your user and granted authority definitions from an XML - file, JDBC datasource or Properties file. Alternatively, you can implement the - single-method UserDetailsService interface and obtain authentication details from - anywhere you like.



    -
  • Event support: Building upon Spring's - ApplicationEvent services, you can write your own listeners - for authentication-related events, along with authorisation-related events. - This enables you to implement account lockout and audit log systems, with - complete decoupling from Acegi Security code.



    -
  • Easy integration with existing databases: Our implementations - have been designed to make it very easy to use your existing - authentication schema and data (without modification). Of course, - you can also provide your own Data Access Object if you wish.



    -
  • Caching: Acegi Security integrates with Spring's EHCACHE factory. - This flexibility means your database (or other authentication - repository) is not repeatedly queried for authentication - information.



    -
  • Pluggable architecture: Every critical aspect of the package - has been modelled using high cohesion, loose coupling, interface-driven - design principles. You can easily replace, customise or extend parts of - the package.



    -
  • Startup-time validation: Every critical object dependency and - configuration parameter is validated at application context startup - time. Security configuration errors are therefore detected early and - corrected quickly.



    -
  • Remoting support: Does your project use a rich client? Not a - problem. Acegi Security integrates with standard Spring remoting - protocols, because it automatically processes the HTTP BASIC - authentication headers they present. Add our BASIC authentication filter - to your web.xml and you're done. You can also easily use RMI or Digest - authentication for your rich clients with a simple configuration statement.



    -
  • Advanced password encoding: Of course, passwords in your - authentication repository need not be in plain text. We support both SHA - and MD5 encoding, and also pluggable "salt" providers to maximise - password security. Acegi Security doesn't even need to see the password - if your backend can use a bind-based strategy for authentication (such as - an LDAP directory, or a database login).



    -
  • Run-as replacement: The system fully supports - temporarily replacing the authenticated principal for the duration of the web - request or bean invocation. This enables you to build public-facing - object tiers with different security configurations than your backend - objects.



    -
  • Transparent security propagation: Acegi Security can automatically - transfer its core authentication information from one machine to another, - using a variety of protocols including RMI and Spring's HttpInvoker.



    -
  • Compatible with HttpServletRequest's security methods: Even though - Acegi Security can deliver authentication using a range of pluggable mechanisms - (most of which require no web container configuration), we allow you to access - the resulting Authentication object via the getRemoteUser() and other - security methods on HttpServletRequest.



    -
  • Unit tests: A must-have of any quality security project, unit - tests are included. Our unit test coverage is very high, as shown in the - coverage report.



    -
  • Built by Maven: This assists you in effectively reusing the Acegi - Security artifacts in your own Maven-based projects.



    -
  • Supports your own unit tests: We provide a number of classes - that assist with your own unit testing of secured business objects. For - example, you can change the authentication identity and its associated - granted authorities directly within your test methods.



    -
  • Peer reviewed: Whilst nothing is ever completely secure, - using an open source security package leverages the continuous design - and code quality improvements that emerge from peer review.



    -
  • Community: Well-known for its supportive community, Acegi Security - has an active group of developers and users. Visit our project resources (below) - to access these services.



    -
  • Apache license. You can confidently use Acegi Security in your project.





-
- -
Project Resources


- Support Forums



- Developer Mailing List



- Downloads -
\ No newline at end of file diff --git a/doc/xdocs/navigation.xml b/doc/xdocs/navigation.xml deleted file mode 100644 index 9a116ff222..0000000000 --- a/doc/xdocs/navigation.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/xdocs/petclinic-tutorial.xml b/doc/xdocs/petclinic-tutorial.xml deleted file mode 100644 index 5b6a83bc42..0000000000 --- a/doc/xdocs/petclinic-tutorial.xml +++ /dev/null @@ -1,168 +0,0 @@ - -Tutorial: Adding Security to Spring Petclinic

To complete this tutorial, you will require a servlet container (such as Tomcat) -and a general understanding of using Spring without Acegi Security. The Petclinic -sample itself is part of Spring and should help you learn Spring. We suggest you -only try to learn one thing at a time, and start with Spring/Petclinic before -Acegi Security. -

-You will also need to download: -

    -
  • Spring 2.0 with dependencies ZIP file
  • -
  • Acegi Security 1.0.2
  • -
-

-Unzip both files. After unzipping Acegi Security, you'll need to unzip the -acegi-security-sample-tutorial.war file, because we need some files that are -included within it. In the code below, we'll refer to the respective unzipped -locations as %spring% and %acegi% (with the latter variable referring to the -unzipped WAR, not the original ZIP). There is no need to setup any environment -variables to complete the tutorial. -

-We now need to put some extra files into Petclinic. The following commands should work: -

-mkdir %spring%\samples\petclinic\war\WEB-INF\lib
-copy %acegi%\acegilogin.jsp %spring%\samples\petclinic\war
-copy %acegi%\accessDenied.jsp %spring%\samples\petclinic\war
-copy %acegi%\WEB-INF\users.properties %spring%\samples\petclinic\war\WEB-INF
-copy %acegi%\WEB-INF\applicationContext-acegi-security.xml %spring%\samples\petclinic\war\WEB-INF
-copy %acegi%\WEB-INF\lib\acegi-security-1.0.0.jar %spring%\samples\petclinic\war\WEB-INF\lib
-copy %acegi%\WEB-INF\lib\oro-2.0.8.jar %spring%\samples\petclinic\war\WEB-INF\lib
-copy %acegi%\WEB-INF\lib\commons-codec-1.3.jar %spring%\samples\petclinic\war\WEB-INF\lib
-
-

Edit %spring%\samples\petclinic\war\WEB-INF\web.xml and insert the following block of code. -

-<filter>
-  <filter-name>Acegi Filter Chain Proxy</filter-name>
-  <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
-  <init-param>
-    <param-name>targetClass</param-name>
-    <param-value>org.acegisecurity.util.FilterChainProxy</param-value>
-  </init-param>
-</filter>
-
-<filter-mapping>
-  <filter-name>Acegi Filter Chain Proxy</filter-name>
-  <url-pattern>/*</url-pattern>
-</filter-mapping>
-
-Next, locate the "contextConfigLocation" parameter, and add a new line into the existing param-value. -The resulting block will look like this: -
-<context-param>
-  <param-name>contextConfigLocation</param-name>
-  <param-value>
-    /WEB-INF/applicationContext-jdbc.xml
-    /WEB-INF/applicationContext-acegi-security.xml
-  </param-value>
-</context-param>
-
-

-To make it easier to experiment with the application, now edit -%spring%\samples\petclinic\war\WEB-INF\jsp\footer.jsp. Add a new "logout" link, as shown: -

-<table style="width:100%"><tr>
-  <td><A href="<c:url value="/welcome.htm"/>">Home</A></td>
-  <td><A href="<c:url value="/j_acegi_logout"/>">Logout</A></td>
-  <td style="text-align:right;color:silver">PetClinic :: a Spring Framework demonstration</td>
-</tr></table>
-
-

-Our last step is to specify which URLs require authorization and which do not. Let's -edit %spring%\samples\petclinic\war\WEB-INF\applicationContext-acegi-security.xml. -Locate the bean definition for FilterSecurityInterceptor. Edit its objectDefinitionSource -property so that it reflects the following: -

-<property name="objectDefinitionSource">
-  <value>
-    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
-    PATTERN_TYPE_APACHE_ANT
-    /acegilogin.jsp=IS_AUTHENTICATED_ANONYMOUSLY
-    /**=IS_AUTHENTICATED_REMEMBERED
-  </value>
-</property>
-
-

Start the Hypersonic server (this is just normal Petclinic configuration): -

-cd %spring%\samples\petclinic\db\hsqldb
-server
-
-

-Insert some data (again, normal Petclinic configuration): -

-cd %spring%\samples\petclinic
-build setupDB
-
-

-Use Petclinic's Ant build script and deploy to your servlet container: -

-cd %spring%\samples\petclinic
-build warfile
-copy dist\petclinic.war %TOMCAT_HOME%\webapps
-
-

Finally, start your container and try to visit the home page. -Your request should be intercepted and you will be forced to login.

-Whilst you've now secured your web requests, you might want to stop users -from being able to add clinic visits unless authorized. We'll make it so -you need to hold ROLE_SUPERVISOR to add a clinic visit. -

-In %spring%\samples\petclinic\war\WEB-INF\applicationContext-jdbc.xml, locate -the TransactionProxyFactoryBean definition. Add an additional property after -the existing "preInterceptors" property: -

-<property name="postInterceptors" ref="methodSecurityInterceptor"/>
-
-

-Finally, we need to add in the referred-to "methodSecurityInterceptor" bean definition. -So pop an extra bean definition in, as shown below: -

-<bean id="methodSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
-  <property name="authenticationManager"><ref bean="authenticationManager"/></property>
-  <property name="accessDecisionManager">
-    <bean class="org.acegisecurity.vote.AffirmativeBased">
-      <property name="allowIfAllAbstainDecisions" value="false"/>
-      <property name="decisionVoters">
-        <list>
-          <bean class="org.acegisecurity.vote.RoleVoter"/>
-          <bean class="org.acegisecurity.vote.AuthenticatedVoter"/>
-        </list>
-      </property>
-    </bean>
-  </property>
-  <property name="objectDefinitionSource">
-    <value>
-      org.springframework.samples.petclinic.Clinic.*=IS_AUTHENTICATED_REMEMBERED
-      org.springframework.samples.petclinic.Clinic.storeVisit=ROLE_SUPERVISOR
-    </value>
-  </property>
-</bean>
-
-

-Redeploy your web application. Use the earlier process to do that. Be careful to -ensure that the old Petclinic WAR is replaced by the new Petclinic WAR in your -servlet container. Login as "marissa", who has ROLE_SUPERVISOR. You will be able to -then view a customer and add a visit. Logout, then login as anyone other than Marissa. -You will receive an access denied error when you attempt to add a visit. -

-To clean things up a bit, you might want to wrap up by hiding the "add visit" link -unless you are authorized to use it. Acegi Security provides a tag library to help -you do that. Edit %spring%\samples\petclinic\war\WEB-INF\jsp\owner.jsp. Add -the following line to the top of the file: -

-<%@ taglib prefix="authz" uri="http://acegisecurity.org/authz" %>
-
-Next, scroll down and find the link to "add visit". Modify it as follows: -
-<authz:authorize ifAllGranted="ROLE_SUPERVISOR">
-  <FORM method=GET action="<c:url value="/addVisit.htm"/>" name="formVisitPet<c:out value="${pet.id}"/>">
-  <INPUT type="hidden" name="petId" value="<c:out value="${pet.id}"/>"/>
-  <INPUT type="submit" value="Add Visit"/>
-  </FORM>
-</authz:authorize>          
-
-

-These steps can be applied to your own application. Although we do suggest -that you visit http://acegisecurity.org -and in particular review the "Suggested Steps" for getting started with Acegi -Security. The suggested steps are optimized for learning Acegi Security quickly -and applying it to your own projects. It also includes realistic time estimates -for each step so you can plan your integration activities.

\ No newline at end of file diff --git a/doc/xdocs/policies.xml b/doc/xdocs/policies.xml deleted file mode 100644 index 1a07a33976..0000000000 --- a/doc/xdocs/policies.xml +++ /dev/null @@ -1,103 +0,0 @@ - -Project Policies and Procedures

The following policies and procedures are intended to ensure that Acegi Security will - continue to achieve its project objectives and support the community in the context of an - expanding development team. - -

- The following was unanimously supported by the community supporting following - discussion - on acegisecurity-developer. The policies and procedures below represent version 1.0 - and are effective 1 August 2005. -

    - -
  • - This project uses JIRA. Please log a task in JIRA for any changes you make to SVN, with the exception of very minor changes that users are unlikely to ever be interested in searching for and/or the change affects code that has never been in an officially released version of the project (eg ongoing changes to a new feature in SVN HEAD that hasn't been released previously).



    -
  • - -
  • - Any users running from SVN HEAD are warmly encouraged to join acegisecurity-cvs so that they can keep an eye on commit comments. Developers are encouraged to join acegisecurity-cvs and read the commit comments. If anyone has a concern with any commit, please raise it on acegisecurity-developer so that the broader community can participate (not acegisecurity-cvs). Alternatively, contact the author of the change directly if you think that would be more appropriate or diplomatic.



    -
  • - -
  • - Please make your commit comments informative, yet not too detailed. Detailed comments are ideally placed in the JIRA task. In the case of a contribution by a non-developer, please use the SVN commits to reflect who provided the contribution and add that person's name to /pom.xml in the contributors section. If the contributors section does not list the name of someone who has contributed accepted code, please add them or let me know so that I can do so.



    -
  • - -
  • - If you add a major new feature, please announce it on acegisecurity-developer. That way people using the project have an idea of what is coming up in the next release, and any implementation-specific comments can be received prior to the first release when users will start expecting some degree of consistency and stability. It also encourages people to try out your new feature.



    -
  • - -
  • - Please make sure /docs/xdocs/changes.xml has a reference to JIRA for the upcoming release version. You don't need to add the name of contributors to /doc/xdocs/changes.xml, as acknowledgement is already provided via /pom.xml, source code @author tags, the SVN commit message, and typically a JIRA task.



    -
  • - -
  • - Please edit /docs/xdocs/upgrade/upgrade-xx-yy.html if you make a change that is significant and you think users who are upgrading should be aware of it. Equally, users are encouraged to consult the upgrade-xx-yy.html file before they deploy subsequent official release JARs.



    -
  • - -
  • - Please use Jalopy with the /jalopy.xml file to format your Java code before checkin. This keeps our code consistent and ensures the license message is correct. There are plugins for all major IDEs.



    -
  • - -
  • - The /sandbox can be used to obtain feedback from fellow developers and the community about your code, general approach or new ideas. If you have SVN rights, please use /sandbox instead of emailing ZIP files to other developers for feedback. The community should understand that code in the sandbox is unsupported, subject to refactoring, may not have any unit tests, and may be removed at any time. The /sandbox will never be included in official release ZIPs. It's a "scratching pad" only.



    -
  • - -
  • - Unit tests are important to any security project, and we have a good history of high coverage. You can view the latest coverage report online (rebuilt every 24 hours). Please keep an eye on coverage and don't hesitate to add more unit tests. Please do not check code into /core unless it has at least an exercising unit test - use the /sandbox instead.



    -
  • - -
  • - Never check in code if the unit tests fail. This means, at minimum, successfully running "mvn test" from /core. Always name your unit test classes so they end in "*Tests" - this ensures that Maven picks them up. If there is code in SVN which you didn't write and it is breaking the unit tests, please correct it yourself - don't leave SVN "broken" whilst waiting for the responsible developer to address it (the delay causes confusing and long-running threads on the list and forum). You can always rollback to the previous working version if in doubt of how the class works (just remember to comment the commit appropriately and let the author know).



    -
  • - -
  • - Please update the reference guide and JavaDocs for any new major features. The JavaDocs should always be correct. The reference guide may be kept updated with less rigor, although please briefly discuss any major new features. XMLmind can be used if you don't have a DocBook editor.



    -
  • - -
  • - Developers please keep an eye on the Acegi Security forum. It's a very active forum, and it takes a lot of work if not shared around. Please don't hesitate to reply to users - I try to read every thread and correct/confirm the situation if someone mentions they're unsure. I also will generally send developers an email if there's a question I can't answer as I didn't write the code.



    -
  • - -
  • - In the future, I will put to vote any proposed new developers. New developers will be firstly encouraged to attach patches to JIRA tasks to illustrate their understanding of the project, or, if they're long-time users, they might be given access without this JIRA stage if they're undertaking a major new feature.



    -
  • - -
  • - Developers should be subscribed to acegisecurity-developer. Obviously it would take significant time to read every thread, but reading the high priority messages (as indicated by the subject line) is needed to ensure we all have a way of communicating.



    -
  • - -
  • - Please do not hesitate to assign yourself any JIRA task that is unassigned, or assigned to me and not in the "In Progress" status. Also feel free to approach fellow developers to volunteer to work on tasks they might be assigned but haven't started.



    -
  • - -
  • - No code in SVN is "sacred". If you have a good idea or refactoring for an area of code that someone else wrote, raise it on acegisecurity-developer or contact the author directly. Please don't commit changes to such code unless it is a unit test failure correction, or you've firstly raised it on the acegisecurity-developer list or directly with the author.



    -
  • - -
  • - People's priorities are ever-changing, and we're all short on time. For this reason it's perfectly understandable that over time developers will move on to other things. This is not a negative reflection in any way - just part of any long-term project. If a developer no longer has the time or inclination to participate in the project , please send an email to acegisecurity-developer or myself. I will remove the SVN rights and reassign any JIRA tasks. Importantly, this helps find a new maintainer of the former developer's code (or, in very extreme cases, their code might be relocated to the sandbox or removed).



    -
  • - -
  • - Use CDATA inside XML files for multi-line properties. There is no tab/space policy for XML files, although try to maintain whatever the file is already using. The tab/space policy for Java files is managed by Jalopy.



    -
  • - -
  • - Keep the warm community spirit. The Spring community is a nice place to be - especially compared with some of the other open source communities out there where people are abused, ignored, insulted or excluded. No policy or procedure (including those above) should ever compromise operating in a considerate and diplomatic manner that respects the dignity of each individual member of the community. If in doubt, please contact me directly first. If I am ever guilty of this, please let me know and I will correct myself.



    -
  • - -
- -

Thanks for your help in connection with the above. If you have any suggestions for improving these - policies and procedures, please use the acegisecurity-developer list to raise them. - -

- Ben Alex

- Project Admin - -

- $Id$ - - - -

\ No newline at end of file diff --git a/doc/xdocs/powering.xml b/doc/xdocs/powering.xml deleted file mode 100644 index 9590571430..0000000000 --- a/doc/xdocs/powering.xml +++ /dev/null @@ -1,39 +0,0 @@ - -Products Using Acegi Security

Many open source and commercial products either use Acegi Security or at least - support it. Following is a partial list of such products. If you've integrated Acegi - Security with some other product, please let us know (preferably with a URL - to some page explaining the integration/use)... - -

    -
  • A global financial institution uses Acegi Security's SiteMinder integration in a physical security management application.



  • -
  • A central bank that uses Acegi Security for many of its internal applications with the CAS integration.



  • -
  • Several Australian Government departments use Acegi Security for securing SOAP-based web services and web applications.



  • -
  • Enterprise Systems and Services at Rutgers University uses Acegi Security in conjunction with JA-SIG Central Authentication Service to provide authentication and authorization capabilities to its applications including those used by staff and students as well as those utilized by web services.



  • -
  • Elastic Path uses Acegi Security for security.



  • -
  • Plus many more... ;-)



  • -
\ No newline at end of file diff --git a/doc/xdocs/reference.xml b/doc/xdocs/reference.xml deleted file mode 100644 index 42c087e1d0..0000000000 --- a/doc/xdocs/reference.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - Reference Documentation - - - -
- - - - - - - - - - - - - - - - - -
DocumentDescription
- Reference Guide HTML Single Page - - The reference guide in a single html page. -
- Reference Guide PDF - - The PDF version of the reference guide. -
-
-
- -
diff --git a/doc/xdocs/standalone.xml b/doc/xdocs/standalone.xml deleted file mode 100644 index 9e8a3e293c..0000000000 --- a/doc/xdocs/standalone.xml +++ /dev/null @@ -1,50 +0,0 @@ - -Acegi Security Use Without Spring

Sometimes we get asked can Acegi Security be used without Spring. - This page provides a detailed answer.

Acegi Security started out as a method interceptor for Spring IoC container - managed beans. Typically such beans provide services layer functions. - Over time Acegi Security grew to offer authentication services, ThreadLocal management, - web request filtering, extra AOP support, - ACL features, additional authentication mechanisms and so on (for those interested, - see our change log).

There's plenty written about why the - Spring Framework - is a good fit for modern applications. If you're not familiar with the benefits - Spring offers, please take a few minutes to learn more about it. In numerous - situations Spring will save you many months (or even years) of development time. - Not to mention your solutions will be better architected - (designed), better coded (implemented), and better supported (maintained) in the future. -

Acegi Security relies on the Spring IoC container to wire its classes, and execute lifecycle - methods such as afterPropertiesSet(). Some Acegi Security classes also - publish events to the ApplicationContext, although you could provide a mock - implementation of ApplicationContext easily enough which no-ops the method. - In other words, if you particularly didn't want Spring in your application, you could - avoid its use by writing equivalent getter, setter and lifecycle invocation processes - in standard Java code. This is a natural consequence of the Spring way of development, - which emphasises framework independence (it is not because we think there are good - reasons people would not use Spring).

If it sounds too hard (it's not) or counter-productive (it is) to replace Spring's IoC - services, don't forget you can always deploy Acegi Security and the Spring - IoC container solely for configuring Acegi Security. Spring does not mandate its - use in every part of your application. It will work quite successfully doing nothing more than - acting as a configuration mechanism for Acegi Security. Whilst some may regard this as excessive, - it's really no different than the traditional approach of every framework having its very - own XML or other proprietary configuration system. The main difference is that Spring is an - actual de facto standard, and you can gradually introduce it to other parts of your application - over time (if desired).

Acegi Security does not use any other Spring capabilities. Most notably, the - entire architecture is based around Filters, not Spring's MVC framework. - This allows it to be used with any MVC framework, or even with just straight JSPs. - Acegi Security uses the AOP Alliance and AspectJ interfaces for method interception - - it does not use any Spring-specific interfaces. As a consequence, Acegi Security is very - portable to applications that do not leverage any of Spring's capabilities. We should note - there are several very simple data access objects (DAOs) that use Spring's JDBC abstraction - layer, although each of these are defined by a simple interface and it is very common in - even native Spring-powered applications for these to be re-implemented using the application's - persistence framework of choice (eg Hibernate). - -

In summary, we recommend you take a look at Spring and consider using it in your - applications. Irrespective of whether you do so or not, we strongly recommend you use it - for configuration and lifecycle management of Acegi Security. If that is also not desired, - Acegi Security can easily be executed without Spring at all, providing you implement - similar IoC services. Acegi Security has very minimal dependencies directly on Spring, - with it being useful in many non-Spring applications and with non-Spring frameworks. - - -

\ No newline at end of file diff --git a/doc/xdocs/suggested.xml b/doc/xdocs/suggested.xml deleted file mode 100644 index 462ac943df..0000000000 --- a/doc/xdocs/suggested.xml +++ /dev/null @@ -1,105 +0,0 @@ - -Acegi Security Suggested Steps

Presented below are the steps we encourage you to take in order to gain the most - out of Acegi Security in a realistic timeframe. -

    -
  1. - First of all, deploy the "Tutorial Sample", which is included in the main distribution - ZIP file. The sample doesn't do a great deal, but it does give you a template that can - be quickly and easily used to integrate into your own project.



    - - Estimated time: 30 minutes.



    -
  2. - -
  3. - Next, follow the Petclinic tutorial, which - covers how to add Acegi Security to the commonly-used Petclinic sample application - that ships with Spring. This will give you a hands-on approach to integrating - Acegi Security into your own application.



    - - Estimated time: 1 hour.



    -
  4. - -
  5. - Next, review the Reference Guide, and in particular - Part I. It has been designed to give you a solid overview. Go through the beans - defined in the "Tutorial Sample" and understand their main purpose within the overall - framework. Once you understand this, you'll have no difficulty moving on to more - complex examples. You can also experiment in the Petclinic tutorial that you - implemented in the last step.



    - - Estimated time: 1 day.



    -
  6. - -
  7. - If you have relatively simple security needs, you can probably start to integrate - Acegi Security into your application at this point. Just use the "Tutorial Sample" - as your basis (now that you understand how it works). Those with more complicated - requirements should review the "Contacts Sample" application. - This will probably involve deploying acegi-security-sample-contacts-filter.war, - which is also included in the release ZIP file.



    - - The purpose of understanding the "Contacts Sample" is to get a better feel for how method - security is implemented, particularly with domain object access control lists. This will - really round-out the rest of the framework for you.



    - - The actual java code - is a completely standard Spring application, except ContactManagerBackend - which shows how we create and delete ACL permissions. The rest of the Java code has no - security awareness, with all security services being declared in the XML files - (don't worry, there aren't any new XML formats to learn: they're all standard Spring IoC container - declarations or the stock-standard web.xml). The main - XML files to review are - applicationContext-acegi-security.xml (from the filter webapp), - applicationContext-common-authorization.xml, - applicationContext-common-business.xml (just note we add contactManagerSecurity to the services layer target bean), and - web.xml (from the filter webapp). - The XML definitions are comprehensively discussed in the - Reference Guide. -



    - - Please note the release ZIP files do not include the sample application Java source code. You - will need to download from SVN if you would like to access the Java sources.



    - - Estimated time: 1-2 days.



    -
  8. - -
  9. By now you will have a good grasp on how Acegi Security works, and all that is left to - do is design your own application's implementation. -



    - - We strongly recommend that you start your actual integration with the "Tutorial Sample". - Don't start by integrating with the "Contacts Sample", even if you have complex needs. - Most people reporting problems on the forums do so because of a configuration problem, - as they're trying to make far too many changes at once without really knowing what - they're doing. Instead, make changes one at a time, starting from the bare bones configuration - provided by the "Tutorial Sample".



    - - If you've followed the steps above, and refer back to the - Reference Guide, - forums, and - FAQ - for help, you'll find it pretty easy to implement Acegi Security in your application. - Most importantly, you'll be using a security framework that offers you complete container - portability, flexibility, and community support - without needing to write and maintain your - own code.



    - - Estimated time: 1-5 days.



    - -
  10. - -
- -

Please note the time estimates are just that: estimates. They will vary considerably depending - on how much experience you have, particularly with Java and Spring. They will also vary depending - on how complex your intended security-enabled application will be. Some people need to push the domain - object instance access control list capabilities to the maximum, whilst others don't even need anything - beyond web request security. The good thing is Acegi Security will either directly support your future - needs, or provide a clearly-defined extension point for addressing them. - -

- We welcome your feedback about how long it has actually taken you to complete each step, so we - can update this page and help new users better assess their project timetables in the future. - Any other tips on what you found helpful in learning Acegi Security are also very welcome. - - -

\ No newline at end of file diff --git a/doc/xdocs/upgrade/upgrade-03-04.xml b/doc/xdocs/upgrade/upgrade-03-04.xml deleted file mode 100644 index 71007bc590..0000000000 --- a/doc/xdocs/upgrade/upgrade-03-04.xml +++ /dev/null @@ -1,48 +0,0 @@ - -Acegi Security - Upgrading from version 0.3 to 0.4

Several changes were made between version 0.3 and 0.4 of the project. -These changes increased the modularity of the code, enhanced unit testing, -made package roles clearer, and added compelling alternatives to container -adapters and using web.xml security constraints to protect HTTP resources. - -

Unfortunately, changes to the API and package locations were required. The -following should help most casual users of the project update their -applications: - -

    -
  • All references to net.sf.acegisecurity.SecurityInterceptor become - net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor.
  • - -
  • All references to net.sf.acegisecurity.MethodDefinitionAttributes become - net.sf.acegisecurity.intercept.method.MethodDefinitionAttributes.
  • - -
  • All references to net.sf.acegisecurity.adapters.AutoIntegrationFilter become - net.sf.acegisecurity.ui.AutoIntegrationFilter (see your web.xml).
  • - -
  • If you're using container adapters (extremely likely), consider replacing - them with the net.sf.acegisecurity.ui.webapp package. This will avoid - the need to have JARs in your container classloader, and is a lot cleaner. - Refer to the reference documentation or Contacts sample application.
  • - -
  • If you're using web.xml s for securing HTTP URLs - (extremely likely), consider replacing it with the - net.sf.acegisecurity.intercept.web package. This will give you considerably - more flexibility, and reuse the same concepts as you'd be familiar with - via the method security interception system. Refer to the reference - documentation or Contacts sample application.
  • - -
  • The Contacts sample application now builds two distributions: contacts.war - can be instantly deployed without configuring any container adapters, - whilst contacts-container-adapter.war still uses container adapters. The - contacts.war uses the net.sf.acegisecurity.intercept.web package to - protect HTTP URLs, rather than web.xml s.
  • - -
  • If you're using the Jetty container adapter, please check the jetty.xml - requirements in the reference documentation. There has been a minor change.
  • -
- -

-We hope you find the new features useful in your projects. - - - -

\ No newline at end of file diff --git a/doc/xdocs/upgrade/upgrade-04-05.xml b/doc/xdocs/upgrade/upgrade-04-05.xml deleted file mode 100644 index 255a9c5bb6..0000000000 --- a/doc/xdocs/upgrade/upgrade-04-05.xml +++ /dev/null @@ -1,54 +0,0 @@ - -Acegi Security - Upgrading from version 0.4 to 0.5

The following should help most casual users of the project update their -applications: -

    - -
  • All filters are now loaded via FilterToBeanProxy. The FilterToBeanProxy - obtains the filter from a Spring application context via the - WebApplicationContextUtils.getApplicationContext() method. Refer to the - reference documentation to see the new configuration of filters.
  • - -
  • SecurityEnforcementFilter now requires an AuthenticationEntryPoint - and PortResolver. Refer to the reference documentation to see the - alternatives AuthenticationEntryPoint implementations available. Simply - use the PortResolverImpl for the PortResolver requirement.
  • - -
  • Any of your login or login failure pages that previously referred to - AuthenticationProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY - should now use - net.sf.acegisecurity.ui.AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY.
  • - -
  • DaoAuthenticationProvider no longer provides setters for case sensitivity - handling. The respective AuthenticationDao implementations should decide - whether or not to return User instances reflecting the exact case of the - requested username. The new PlaintextPasswordEncoder offers a setter for - ignoring the password case (defaults to require exact case matches).
  • - -
  • DaoAuthenticationProvider now provides caching. Successful authentications - return DaoAuthenticationTokens. You must set the mandatory "key" property - on DaoAuthenticationProvider so these tokens can be validated. You may - also wish to change the "refreshTokenInterval" property from the default - of 60,000 milliseconds.
  • - -
  • If you're using container adapters, please refer to the reference - documentation as additional JARs are now required in your container - classloader.
  • - -
  • Whilst not really a change needed to your program, if you're using - Acegi Security please consider joining the acegisecurity-developer mailing - list. This is currently the best way to keep informed about the project's - status and provide feedback in design discussions. You can join at - https://lists.sourceforge.net/lists/listinfo/acegisecurity-developer. - Please continue using the Spring Users mailing list for general support.
  • -
- -

-There are also lots of new features you might wish to consider for your -projects. These include CAS integration, pluggable password encoders -(such as MD5 and SHA), along with pluggable salt sources. We hope you find -the new features useful in your projects. - - - - -

\ No newline at end of file diff --git a/doc/xdocs/upgrade/upgrade-05-06.xml b/doc/xdocs/upgrade/upgrade-05-06.xml deleted file mode 100644 index 8348c29701..0000000000 --- a/doc/xdocs/upgrade/upgrade-05-06.xml +++ /dev/null @@ -1,76 +0,0 @@ - -Acegi Security - Upgrading from version 0.3 to 0.4

-The following should help most casual users of the project update their -applications: -

    -
  • -Locate and remove all property references to - DaoAuthenticationProvider.key and - DaoAuthenticationProvider.refreshTokenInterval.
  • - -
  • If you are using DaoAuthenticationProvider and either (i) you are using - container adapters or (ii) your code relies on the Authentication object - having its getPrincipal() return a String, you must set the new - DaoAuthenticationProvider property, forcePrincipalAsString, to true. - By default DaoAuthenticationProvider returns an Authentication object - containing the relevant User, which allows access to additional properties. - Where possible, we recommend you change your code to something like this, - so that you can leave forcePrincipalAsString to the false default:



    - - String username = authentication.getPrincipal();

    - if (authentication.getPrincipal() instanceof User) {

    - username = ((User) authentication.getPrincipal()).getUsername();

    - } -


    -
  • - -
  • The signature of AuthenticationDaos have changed. In concrete - implementations, modify the User to UserDetails, as shown below:



    - - public User loadUserByUsername(String username)

    - throws UsernameNotFoundException, DataAccessException {



    - - to:



    - - public UserDetails loadUserByUsername(String username)

    - throws UsernameNotFoundException, DataAccessException {



    -
    - - Existing concrete implementations would be returning User, which implements - UserDetails, so no further code changes should be required. -
  • -
  • Similar signature changes (User -> UserDetails) are also required to any - custom implementations of UserCache and SaltSource.
  • - -
  • Any custom event listeners relying on AuthenticationEvent should note a - UserDetails is now provided in the AuthenticationEvent (not a User).
  • - -
  • CAS users should note the CasAuthoritiesPopulator interface signature has - changed. Most CAS users will be using DaoCasAuthoritiesPopulator, so this - change is unlikely to require any action.
  • - -
  • Please check your web.xml for whether you are using AutoIntegrationFilter. - Previously this class was loaded directly by web.xml as a filter. It is - now recommended to load it via FilterToBeanProxy and define it as a - bean in your application context. This usually involves making the entry - in web.xml match the following:



    - - <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>

    - </init-param>

    - </filter>

    -
    -



    - Then add the following to applicationContext.xml:



    - - <bean id="autoIntegrationFilter" class="net.sf.acegisecurity.ui.AutoIntegrationFilter"/>

    -
    -
  • -
- - -

\ No newline at end of file diff --git a/doc/xdocs/upgrade/upgrade-06-070.xml b/doc/xdocs/upgrade/upgrade-06-070.xml deleted file mode 100644 index 73bf74289b..0000000000 --- a/doc/xdocs/upgrade/upgrade-06-070.xml +++ /dev/null @@ -1,55 +0,0 @@ - -Acegi Security - Upgrading from version 0.6 to 0.7

-The following should help most casual users of the project update their -applications: -

    -
  • UserDetails now has two extra methods. Most people who have extended -Acegi Security's default User implementation of UserDetails will be fine, as -the constructor sets sensible defaults for the extra methods. People who -have written their own UserDetails implementation from scratch will need to -add the additional two methods. Returning true to both methods will normally -be correct. -
  • -
  • AutoIntegrationFilter has been removed. User should instead use - HttpSessionIntegrationFilter (in most cases), or HttpRequestIntegrationFilter - (if using most container adapters) or JbossIntegrationFilter (if using the - JBoss container adapter).
  • - -
  • MethodDefinitionMap, which is usually used by MethodSecurityInterceptor - for its objectDefinitionSource property, has been changed. From 0.7.0, when - MethodDefinitionMap is queried for configuration attributes associated with - secure MethodInvocations, it will use any method matching in the method - invocation class (as it always has) plus any method matching any interface - the MethodInvocation class directly implements. So consider a PersonManager - interface, a PersonManagerImpl class that implements it, and a definition of - PersonManager.findAll=ROLE_FOO. In this example, any query for either - PersonManager.findAll OR PersonManagerImpl.findAll will return ROLE_FOO. - As we have always encouraged definition against the interface names (as per - this example), this change should not adversely impact users. This change - was necessary because of the new MethodDefinitionSourceAdvisor (see below). - Refer to the MethodDefinitionMap JavaDocs for further clarification.
  • - -
  • MethodDefinitionSourceAdvisor can now be used instead of defining proxies - for secure business objects. The advisor is fully compatible with both - MethodDefinitionMap and MethodDefinitionAttributes. Using an advisor allows - caching of which methods the MethodSecurityInterceptor should handle, thus - providing a performance benefit as MethodSecurityInterceptor is not called - for public (non-secure) objects. It also simplifies configuration.
  • - -
  • MethodSecurityInterceptor has moved from - net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor to - net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor. - A simple find and replace will suffice to update your application contexts.
  • - -
  • All of the EH-CACHE cache implementations provided with Acegi Security have - now been refactored to use a net.sf.ehcache.Cache obtained from - EhCacheManagerFactoryBean, which is included with Spring 1.1.1 and above. - See http://opensource.atlassian.com/confluence/spring/display/DISC/Caching+the+result+of+methods+using+Spring+and+EHCache - for more about this bean, or the Contacts sample application for how to - configure the EH-CACHE implementations provided with Acegi Security. - Note the "cache" property is now required, and the old internally-managed - cache properties have been removed.
  • -
- - -

\ No newline at end of file diff --git a/doc/xdocs/upgrade/upgrade-070-080.xml b/doc/xdocs/upgrade/upgrade-070-080.xml deleted file mode 100644 index 2ce1289095..0000000000 --- a/doc/xdocs/upgrade/upgrade-070-080.xml +++ /dev/null @@ -1,41 +0,0 @@ - -Acegi Security - Upgrading from version 0.7.0 to 0.8.0

-The following should help most casual users of the project update their -applications: - -

    - -
  • HttpSessionIntegrationFilter has been removed. Use net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter instead. - Note you will need to set the mandatory "context" property to something like "net.sf.acegisecurity.context.security.SecureContextImpl". - It's not the default because we want no dependencies between the context package and the rest of Acegi Security.



  • - -
  • Filter ordering has changed. See the reference guide for confirmation of the correct ordering. Basically you should have - HttpSessionContextIntegrationFilter appear before any of your authentication mechanisms.



  • - -
  • IoC container hosted filter chains can now be used instead of lengthy web.xml declarations. See the reference guide or the - Contacts Sample for further information.



  • - -
  • Certain classes have been moved to new packages: ContextHolderAwareRequestWrapper (and its filter), - AuthenticationSimpleHttpInvokerRequestExecutor, ContextPropagatingRemoteInvocation, - SecureContext (and its implementation). These classes were moved as part of refactorings aimed at - improving the simplicity of the project's design.



  • - -
  • If you wish to use the new ConcurrentSessionController you must declare the HttpSessionEventPublisher context listener in your - web.xml



  • - -
  • The JaasAuthenticationCallbackHandler interface has had it's setAuthentication method removed. - The handle method now takes both the Callback and Authentication objects as arguments.



  • - -
  • Added AuthenticationException to the AutenticationEntryPoint.commence method signature.



  • - -
  • Added AccessDeniedException to the SecurityEncorcementFilter.sendAccessDeniedError method signature.



  • - -
  • The Authentication.getDetails() no longer returns simply the IP address used for authentication. - It now returns a WebAuthenticationDetails instance, which contains the IP address, session information, - and can be extended to store further details.



  • - -
- - - -

\ No newline at end of file diff --git a/doc/xdocs/upgrade/upgrade-080-090.xml b/doc/xdocs/upgrade/upgrade-080-090.xml deleted file mode 100644 index fc3271ecd1..0000000000 --- a/doc/xdocs/upgrade/upgrade-080-090.xml +++ /dev/null @@ -1,95 +0,0 @@ - -Acegi Security - Upgrading from version 0.8.0 to 0.9.0

-The following should help most casual users of the project update their -applications: - -

    - -
  • The most significant change in 0.9.0 is that ContextHolder and all of its - related classes have been removed. This significant change was made for the sake of consistency - with the core Spring project's approach of a single ThreadLocal per use case, - instead of a shared ThreadLocal for multiple use cases as the previous - ContextHolder allowed. This is an important change in 0.9.0. Many applications - will need to modify their code (and possibly web views) if they directly interact with the old - ContextHolder. The replacement security ThreadLocal is called - - SecurityContextHolder and provides a single getter/setter for a - SecurityContext. - SecurityContextHolder guarantees to never return a null SecurityContext. - SecurityContext provides single getter/setter for Authentication.



    - - To migrate, simply modify all your code that previously worked with ContextHolder, - SecureContext and Context to directly call SecurityContextHolder - and work with the SecurityContext (instead of the now removed Context - and SecureContext interfaces).



    - - For example, change:

    - - SecureContext ctx = SecureContextUtils.getSecureContext();

    -
    - to:

    - - SecurityContext ctx = SecurityContextHolder.getContext();

    -
    -

    - and change:

    - - <bean id="httpSessionContextIntegrationFilter" class="net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter">

    - <property name="context"><value>net.sf.acegisecurity.context.security.SecureContextImpl</value></property>

    - </bean>

    -
    - to:

    - - <bean id="httpSessionContextIntegrationFilter" class="net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter">

    - <property name="context"><value>net.sf.acegisecurity.context.SecurityContextImpl</value></property>

    - </bean>

    -
    -

    - - We apologise for the inconvenience, but on a more positive note this means you receive strict - type checking, you no longer need to mess around with casting to and from Context - implementations, your applications no longer need to perform checking of null and - unexpected Context implementation types.



  • - -
  • AbstractProcessingFilter has changed its getter/setter approach used for customised - authentication exception directions. See the - AbstractProcessingFilter JavaDocs to learn more.



  • - -
  • AnonymousProcessingFilter now has a removeAfterRequest property, which defaults to true. This - will cause the anonymous authentication token to be set to null at the end of each request, thus - avoiding the expense of creating a HttpSession in HttpSessionContextIntegrationFilter. You may - set this property to false if you would like the anoymous authentication token to be preserved, - which would be an unusual requirement.



  • - -
  • Event publishing has been refactored. New event classes have been added, and the location of - LoggerListener has changed. See the net.sf.acegisecurity.event package.

    -

    - For example, change:

    - - <bean id="loggerListener" class="net.sf.acegisecurity.providers.dao.event.LoggerListener"/>

    -
    - to:

    - - <bean id="loggerListener" class="net.sf.acegisecurity.event.authentication.LoggerListener"/> -



    -
  • - -
  • Users of the <authz:authentication> JSP tag will generally need to set the operation - property equal to "username", as reflection is now used to retrieve the property displayed.



  • - -
  • - Users of net.sf.acegisecurity.wrapper.ContextHolderAwareRequestFilter should note that it has been - renamed to net.sf.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter.



    -
  • - -
  • - The concurrent session support handling has changed. Please refer to the Reference Guide to - review the new configuration requirements.



    -
  • - - -
- - - -

\ No newline at end of file diff --git a/doc/xdocs/upgrade/upgrade-090-100.xml b/doc/xdocs/upgrade/upgrade-090-100.xml deleted file mode 100644 index 7b2d897653..0000000000 --- a/doc/xdocs/upgrade/upgrade-090-100.xml +++ /dev/null @@ -1,92 +0,0 @@ - -Acegi Security - Upgrading from version 0.8.0 to 1.0.0

-The following should help most casual users of the project update their -applications: -

    - -
  • The top level package name has changed. Simply find "net.sf.acegisecurity" and replace with -"org.acegisecurity".
  • - -
  • -DaoAuthenticationProvider has a property, authenticationDao. This property should now be renamed to -userDetailsService. -
  • - -
  • -In JSPs, each "authz" taglib prefix must be changed from uri="http://acegisecurity.sf.net/authz" -to uri="http://acegisecurity.org/authz". -
  • - -
  • net.sf.acegisecurity.providers.dao.AuthenticationDao is now org.acegisecurity.userdetails.UserDetailsService. -The interface signature has not changed. Similarly, User and UserDetails have moved into the latter's package as well. -If you've implemented your own AuthenticationDao, you'll need to change the class it's implementing and quite likely -the import packages for User and UserDetails. In addition, if using JdbcDaoImpl or InMemoryDaoImpl please -note they have moved to this new package.
  • - -
  • Acegi Security is now localised. In net.sf.acegisecurity you will find a messages.properties. It is -suggested to register this in your application context, perhaps using ReloadableResourceBundleMessageSource. -If you do not do this, the default messages included in the source code will be used so this change is -not critical. The Spring LocaleContextHolder class is used to determine the locale of messages included in -exceptions. At present only the default messages.properties is included (which is in English). If -you localise this file to another language, please consider attaching it to a -new JIRA task -so that we can include it in future Acegi Security releases.
  • - -
    - -
  • -org.acegisecurity.ui.rememberme.RememberMeProcessingFilter now requires an authenticationManager property. This will generally -point to an implementation of org.acegisecurity.providers.ProviderManager. -
  • - -
  • -org.acegisecurity.intercept.web.AuthenticationEntryPoint has moved to a new location, -org.acegisecurity.ui.AuthenticationEntryPoint. -
  • - -
  • -org.acegisecurity.intercept.web.SecurityEnforcementFilter has moved to a new location and name, -org.acegisecurity.ui.ExceptionTranslationFilter. In addition, the "filterSecurityInterceptor" -property on the old SecurityEnforcementFilter class has been removed. This is because -SecurityEnforcementFilter will no longer delegate to FilterSecurityInterceptor as it has in the -past. Because this delegation feature has been removed (see SEC-144 for a background as to why), -please add a new filter definition for FilterSecurityInterceptor to the end of your -FilterChainProxy. Generally you'll also rename the old SecurityEnforcementFilter entry in your -FilterChainProxy to ExceptionTranslationFilter, more accurately reflecting its purpose. -If you are not using FilterChainProxy (although we recommend that you do), you will need to add -an additional filter entry to web.xml and use FilterToBeanProxy to access the FilterSecurityInterceptor. -
  • - -
  • -If you are directly using SecurityContextHolder.setContext(SecurityContext) - which is not -very common - please not that best practise is now to call SecurityContextHolder.clearContext() -if you wish to erase the contents of the SecurityContextHolder. Previously code such as -SecurityContextHolder.setContext(new SecurityContextImpl()) would have been used. The revised -method internally stores null, which helps avoids redeployment issue caused by the previous -approaches (see SEC-159 for further details). -
  • - -
    - -
  • -AbstractProcessingFilter.onUnsuccessfulAuthentication(HttpServletRequest, HttpServletResponse) -has changed it signature (SEC-238). If subclassing, please override the new signature. -
  • - -
  • -ExceptionTranslationFilter no longer provides a sendAccessDenied() method. Use the -new AccessDeniedHandler instead if custom handling is required. -
  • - -
  • -There have been some changes to the LDAP provider APIs to allow for future improvements, as detailed in -SEC-264. These -should only affect users who have written their own extensions to the provider. The general LDAP -classes are now in the packages org.acegisecurity.ldap and the org.acegisecurity.userdetails.ldap -package has been introduced. The search and authentication classes now return an -LdapUserDetails -instance. The LdapAuthoritiesPopulator interface and its default implementation now both make use of -LdapUserDetails. Any customized versions should be updated to use the new method signatures. -
  • - -
\ No newline at end of file diff --git a/pom.xml b/pom.xml index b44f24b99c..aea4b217db 100644 --- a/pom.xml +++ b/pom.xml @@ -11,9 +11,6 @@ core-tiger adapters samples - Acegi Security System for Spring