Tom,
Thanks for the link.  That is basically a Runtime equivalent of what I
produced.  The code relies on spring-framework to actually parse through
the classes at runtime, which one of my goals was to not depend on any jars
other than wicket jars and the Java core so I may just create a separate
wicketstuff.

Thanks again for sharing that project with me.

John


On Tue, Mar 4, 2014 at 1:28 PM, Burton, Tom F (DOR)
<[email protected]>wrote:

> Hello John,
>
> Not to further muddy the water or insult the good work that's been done.
> https://github.com/wicketstuff/core/wiki/Annotation
>
> I don't know how widely this project is used, but it sounds like you've
> duplicated and possibly extended the project.  Maybe they could be merged?
>
>
> Tom Burton
>
> -----Original Message-----
> From: Martin Grigorov [mailto:[email protected]]
> Sent: Tuesday, March 04, 2014 1:16 AM
> To: [email protected]
> Subject: Re: AutoMounter Annotation Processor
>
> Hi John,
>
>
> On Wed, Feb 26, 2014 at 7:53 PM, John Sarman <[email protected]> wrote:
>
> > Devs,
> >    Recently, I wanted to integrate wicket-auth-roles with servlet 3.0
> > container security.  What I ultimately did was create a simple
> > SigninPage as so:
> >
> > public class LoginInterceptorPage extends WebPage {
> >
> >    public  LoginInterceptorPage() {
> >          continueToOriginalDestination();
> >    }
> >
> > }
> >
> > In my Application class that extends AuthenticatedWebApplication I
> > implement the getSignInPageClass() to return the LoginInterceptorPage.
> >
> > The trick is to mount the LoginInterceptorPage to a url that the
> > servletContainer will pick up  as a security-contraint.
> > web.xml snippet
> > <security-constraint>
> >         <display-name>Constraint1</display-name>
> >         <web-resource-collection>
> >             <web-resource-name>secure</web-resource-name>
> >             <description/>
> >             <url-pattern>/sec/*</url-pattern>       <!-------------   If
> > this pattern is seen then redirect to login scheme if not logged in  -->
> >         </web-resource-collection>
> >         <auth-constraint>
> >             <description>user</description>
> >             <role-name>USER</role-name>
> >         </auth-constraint>
> >     </security-constraint>
> >
> > and in Application.init()  I added
> > mountPage("sec/login.html",LoginInterceptorPage.class); // maps to a
> > url matching pattern set in web.xml
> >
> > Also I added getSecuritySettings().setAuthorizationStrategy(new
> > AnnotationsRoleAuthorizationStrategy(this));
> > to use the annotation @AuthorizeInstantiation to mark pages or
> > packages as needing authorization.
> >
> > For the WebSession I implement as so:
> > public class ServletContainerAuthenticatedWebSession extends
> > AbstractAuthenticatedWebSession {
> >
> >     private static final long serialVersionUID = 1L;
> >
> >     /**
> >      * @return Current authenticated web session
> >      */
> >     public static ServletContainerAuthenticatedWebSession get() {
> >         return (ServletContainerAuthenticatedWebSession) Session.get();
> >     }
> >
> >     public ServletContainerAuthenticatedWebSession(Request request) {
> >         super(request);
> >     }
> >
> >     @Override
> >     public Roles getRoles() {
> >         if (isSignedIn()) {
> >             return new UserPrincipalRoles();
> >         }
> >         return null;
> >     }
> >
> >     @Override
> >     public boolean isSignedIn() {
> >         return getRequest().getUserPrincipal() != null;
> >     }
> >
> >     public void signOut() {
> >         if (isSignedIn()) {
> >             try {
> >                 getRequest().logout();
> >             } catch (ServletException ex) {
> >                 throw new RuntimeException(ex);
> >             }
> >         }
> >     }
> >
> >     private static HttpServletRequest getRequest() {
> >         return (HttpServletRequest)
> > RequestCycle.get().getRequest().getContainerRequest();
> >     }
> >
> >
> > }
> >
> > Where UserPrincipalRoles is :
> > public class UserPrincipalRoles extends Roles{
> >
> >     public UserPrincipalRoles() {
> >
> >     }
> >
> >     @Override
> >     public boolean hasAllRoles(Roles roles) {
> >         Iterator<String> allRoles = roles.iterator();
> >         boolean result = true;
> >         while(allRoles.hasNext() && result) {
> >             result = getRequest().isUserInRole(allRoles.next());
> >         }
> >         return result;
> >     }
> >
> >     @Override
> >     public boolean hasAnyRole(Roles roles) {
> >        Iterator<String> allRoles = roles.iterator();
> >         boolean result = false;
> >         while(allRoles.hasNext() && !result) {
> >             result = getRequest().isUserInRole(allRoles.next());
> >         }
> >         return result;
> >     }
> >
> >     @Override
> >     public boolean hasRole(String role) {
> >         return getRequest().isUserInRole(role);
> >     }
> >
> >     private static HttpServletRequest getRequest() {
> >      return
> >
> (HttpServletRequest)RequestCycle.get().getRequest().getContainerRequest();
> >     }
> >
> >
> > With this I solely rely on the container to determine if the session
> > is logged in via  getRequest().getUserPrincipal() != null; and role
> > matching using the container.
> >
> > What happens is when a page that is annotated with
> > @AuthorizedInstantion and the user is not authenticated, the
> > AuthenticatedWebApplication.onUnauthorizedInstantiation is triggered
> > which then redirects to the LoginInterceptorPage.  Since the
> > LoginInterceptorPage is mounted as sec/Login.html and the
> > security-constraint is looks for anything in sec/*  this forces the
> > auth-method of the login-config in the web.xml to occur.
> >
> > <login-config>
> >         <auth-method>FORM</auth-method>
> >         <realm-name>file-realm</realm-name>
> >         <form-login-config>
> >             <form-login-page>/login.html</form-login-page>
> >             <form-error-page>/error.html</form-error-page>
> >         </form-login-config>
> >     </login-config>
> >
> > In my case I setup the auth-method to be FORM and added a login.html
> > to the root of the war file.  The login.html:
> > <form action="j_security_check" method=post>
> >     <p><strong>Please Enter Your User Name: </strong>
> >     <input type="text" name="j_username" size="25">
> >     <p><p><strong>Please Enter Your Password: </strong>
> >     <input type="password" size="15" name="j_password">
> >     <p><p>
> >     <input type="submit" value="Submit">
> >     <input type="reset" value="Reset"> </form>
> >
> > I set up the file-realm for testing, but obviously ldap, database,
> > SPENAGO, etc can replace this for production. Also html can be jazzed
> > up :)
> >
> > Once the user successfully authenticated, the servlet container
> > redirects back to sec/login.html which then calls
> > continueToOriginalDestination() and ultimately to the page annotated
> > with  @AuthorizedInstantion, assuming the user had the proper role the
> page would be displayed.
> >
> >
> > This works great.  So from there what I realized is I should mount all
> > pages that are annotated with  @AuthorizedInstantion to a url that is
> > caught in the security-constraint of web.xml.  This I call double
> > checking, that is first the security container automatically
> > intercepts any call to a bookmarkable page ie
> > setResponse(SomeSecurePage.class)  and forces the login page, or if a
> > non bookmarkable call occurs the onUnauthorizedInstantiation is
> > triggered which redirects to the LoginInterceptorPage which is mounted
> > to a url that is mapped in the security-contraint in the web.xml.
> > Furthurmore if a bookmarkable secure page is not mapped to a url
> > matching the security-constraint the  onUnauthorizedInstantiation is
> > triggered which intercepts and forces the login page of the container.
> >
> > Nice, with no changes to wicket I can easily integrate
> > wicket-auth-role to use the servlet 3.0 security. (pre 3.0 the
> > getUserPrincipal and such was not in HttpServletRequest)  Also one
> > could create a login page with wicket and call
> > request.authenticate(user,pass), but login-config did not like it when I
> set the url to that page.
> >
> >
> > All that being said what I needed was a way to AutoMount any page or
> > package that had the  @AuthorizedInstantion annotation.  Based on that
> > I created an AnnotationProcessor that generated source which was a
> > list of url and classes.  Here is a sample of the generated source
> >
> > public class MyAppMountInfo implements MountInfo { @Override public
> > List<Mount> getMountPoints() { List<Mount> ret = new
> > ArrayList<Mount>(); ret.add(new Mount("sec/custom/Page3.shtml",
> > com.example.ui.user2.Page3.class));
> > ret.add(new Mount("sec/yo/Yo.html",
> > com.example.ui.user2.Page4.class));
> > ret.add(new Mount("sec/user.html", com.example.ui.user.Page2.class));
> > ret.add(new
> > Mount("sec/AdminPage.shtml", com.example.ui.admin.AdminPage.class));
> > return ret;
> > }
> > }
> >
> >
> >
> > The class is generated as AppName + MountInfo and implements MountInfo
> > so that in the app code you can do something like so public class
> > AutoMounter {
> >
> >     public static boolean mountAll(WebApplication app) {
> >         String mapInfoClassName = app.getClass().getCanonicalName() +
> > "MountInfo";
> >         try {
> >
> >             MountInfo mountInfo = (MountInfo)
> > Class.forName(mapInfoClassName).newInstance();
> >
> >             for (MountInfo.Mount mp : mountInfo.getMountPoints()) {
> >                 app.mountPage(mp.path, (Class<Page>) mp.pageClass);
> >             }
> >             return true;
> >         } catch (Exception ex) {
> >             return false;
> >         }
> >     }
> > }
> >
> > where MountInfo is:
> > public interface MountInfo {
> >
> >     List<Mount> getMountPoints();
> >
> >     public static class Mount {
> >
> >         String path;
> >         Class<? extends Page> pageClass;
> >
> >         public Mount(String path, Class<? extends Page> pageClass) {
> >             this.path = path;
> >             this.pageClass = pageClass;
> >         }
> >
> >     }
> > }
> >
> >
> > In MyApp,init()  just call AutoMounter.mountAll(this);
> >
> > For the processor to actually generate the code you also nee to add
> > the
> > @AutoMount(secure=true)  to the AppClass, this is the annotation that
> > the processor looks for to process the code.
> >
> > public @interface AutoMount {
> >
> >     String defaultRoot() default "";
> >     String mimeExtension() default "";
> >     boolean secure() default false;
> >     String secureRoot() default "secure"; }
> >
> > When implementing this I also realized that maybe users just wanted to
> > AutoMount pages even without doing the secureMount stuff, so I made it
> > also possible to Mount any page.  To set a Mount Point you add the
> > @MountPoint to a page or package-info if you would like to automount
> > all pages in a package.
> >
> > examples:
> >
> > @MountPoint(path="users/ImportantPage.html")
> > public class ImportantUserPage extends WebPage {...
> >
> > ultimately creates  mountPage("users/ImportantPage.html",
> > com.example.ui.user.ImportantUserPage.class);
> >
> > However assume AutoMount(defaultRoot="users", mimeExtension="php")  is
> > set on the App Class and
> >
> > @MountPoint
> > public class ImportantUserPage extends WebPage {...
> >
> > creates  mountPage("users/ImportantUserPage.php",
> > com.example.ui.user.ImportantUserPage.class);  // Really php it is
> > just to prove a point
> >
> >
> > Finally the reason I initially created this code
> > AutoMount(secure=true, secureRoot="sec") public class MyApp ....
> >
> >
> >
> > @AuthorizedInstantiation({"USERS","ADMIN"})
> > public class SecureUserPage extends WebPage {
> >
> >
> > creates mountPage("sec/SecureUserPage",
> > com.example.ui.user.secure.SecureUserPage.class);
> >
> >
> > I already created code and wonder if I should create a pull request, or
> > make it a wicketstuff or just use it for myself.   I personally think it
> > would be nice in wicket itself but I wanted to ask first before going
> > any further.
> >
>
> I think there is not enough interest in this functionality at the moment.
> There were no requests from Wicket users for supporting this neither in
> Jira nor in the mailing lists.
> I believe this is so because Wicket's authentication/authorization is much
> simpler than the ones in Servlet specification.
>
> Additionally your code will require a new compilation step - the
> annotation processing. So far Wicket has tried to avoid any code generation.
>
> Anyway, I'd love to redirect any potential user to the place where you
> decide to share your implementation - WicketStuff or your own repository.
> If there is more demand later then we can reconsider your offer to donate
> this code to Wicket itself.
>
> Thank you!
>
>
> >
> >
> > Thanks,
> > John Sarman
> >
>

Reply via email to