How to implement admin features/sections in app

104 views
Skip to first unread message

Drew Spencer

unread,
Nov 25, 2011, 9:28:53 AM11/25/11
to google-we...@googlegroups.com
Hey coders,

I'm building an app at the moment that will have regular users and administrators. The part I am building atm is an intranet-like section that allows the admins to upload files to the blobstore (also using app engine), so that users can download them.

I have been using MVP with uibinder, so the FormPanel and FileUpload are baked into the UI. Obviously I only want the upload form to appear if it is an admin user looking at the page. Just wondering what the different approaches to this are, etc?

I am thinking about putting the panel that holds the form in the uibinder template, then programatically adding the FileUpload widget and the appropriate clickhandler and other logic. Is this the best way?

Thanks,

Drew

Vitrums

unread,
Nov 26, 2011, 8:51:22 AM11/26/11
to google-we...@googlegroups.com
since admin privileges are run-time features, deferred binding can't help you in this case, unless you duplicate your project adding some extended admin-only functionalities to redirect admin to, and this solution would be just as bad, as if you implement security facility in an abstraction of GWT <-> [your custom servlets] interactions, avoiding usage of standard application server security means. The reason is that if you look a little bit closer at your issue, the problem is hidden not in rendering buttons, which might be added manually by a user via DOM-inspector, but in the server code and URL processing, which should filtrate the incoming requests to limit unprivileged users from abuse attempts.

Craig Hawkins

unread,
Nov 27, 2011, 7:29:01 AM11/27/11
to Google Web Toolkit
Hi Drew

Secure your server/servlets first and UI second. Make sure all
incoming calls to the server tier deny unauthorized users access to
execute administrative operations. When you do this you don't have to
worry if the user attempts an admin activity in the UI because they
will be denied in the server tier.

For the UI, let it all be downloaded to the client and filter the
controls at runtime. When a user logs in to your app query the server
for their authorized privileges. This authorization information can
be used to hide/customize the UI associated with the server side
operations they are not authorize and authorized to perform.

Craig

Drew Spencer

unread,
Nov 28, 2011, 5:52:49 AM11/28/11
to google-we...@googlegroups.com
Hi guys, and thanks for the answers.

So it seems the answers you have given are two-fold. I hadn't really got to thinking about securing the server yet as I am just building a prototype and still learning as I go. However, now seems as good a time as any to secure the RPC calls. Would something as simple as this do the trick, inside the function in the ProgServiceImpl:

if(loginInfo.isAdminUser())
{
// perform RPC call as usual and return
}
else
{
throw UserNotAdminException("blah");
}

On to the client code... Craig, are you saying that it is best to have all of the admin and regular controls in the uibinder template, and then hide things if the user is not an admin? This seems illogical to me, as most users are not admins so they are downloading code that they will never see? Am I missing something? Is this where deferred binding comes in?

Thanks again for you help. I'll get securing those RPC methods!

Drew

Vitrums

unread,
Nov 28, 2011, 7:46:34 AM11/28/11
to google-we...@googlegroups.com
what you are about to implement is something bigger than a simplified logic of admin/not-admin user, but rather privileged/unprivileged. Therefore in many cases like using CAPTCHA (robot defense), that's a matter of your taste as a web-designer to call the server for serialized UI elements, or merely ask it for an approval to actually render missing UI, which you already got on client since his very first http-request (or one, that sucks an appropriate DOM structure for this A&P particularly). It's really all about statically keeping a session on server side until it expires and mapping it to some privileges (regular user, accountant, manager, sysadmin). To make things easier and have your servlets as smart content providers, build your business logic over some modern MVC framework.

opn

unread,
Nov 28, 2011, 8:11:01 AM11/28/11
to google-we...@googlegroups.com
http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting

have a look at code splitting for not downloading something the user does not need!

Craig Hawkins

unread,
Nov 28, 2011, 9:24:37 AM11/28/11
to Google Web Toolkit
If the difference between the download size of your UI for admins
versus regular users is large than you may want to consider splitting
the UI as suggested elsewhere in this thread. You will have to decide
if this is worth the effort in your case. My understanding of the
client side of GAE applications is that the app is only downloaded
once and stays cached unless the app changes.

Williame

unread,
Nov 28, 2011, 12:33:02 PM11/28/11
to google-we...@googlegroups.com
Agreed, server side access checks must always be there. 

    public String getAuditLogDetail(int id) throws MyException {

    HttpSession sess = getThreadLocalRequest().getSession();
    validSession(sess);

    if (hasAdminAccess(sess)) {
        LocalDbWrapper ldb;
        try {
        ldb = new LocalDbWrapper(servletContext);
        AuditLogDAO dao = new AuditLogDAO();
        return (dao.getLogDetail(ldb, id));
        } catch (LocalDbException e) {
        throw new MyException("Database request failed: "
            + e.getMessage());
        }
    } else
        throw new MyException("Access denied! (getAuditLogDetail)");
    }


Some example client code where app config menu item is only enabled after login and if user has admin rights.  Screens for any user are always downloaded, admin screens are downloaded on demand with code splitting(GWT.runAsync).

// only display menu when admin access
if (Access.hasAccess(me, MyConst.ACCESS_ADMIN)) {
   configMenuItem.setVisible(true);
   configMenuItem.setCommand(appConfigCmd);
}


    Command appConfigCmd = new Command() {
        @Override
        public void execute() {
        if (Access.hasAccess(me, MyConst.ACCESS_ADMIN)) {
            GWT.runAsync(new RunAsyncCallback() {

            @Override
            public void onFailure(Throwable reason) {
                Window.alert("GWT.runAsync failed for App Config panel:"
                    + reason.getMessage());
            }

            @Override
            public void onSuccess() {
                uberContent.clear();
                ConfigPanel panel = new ConfigPanel(me);
                uberContent.add(panel);
                placePanel(800, 1300);
            }
            });
        }
        }
    };

Drew Spencer

unread,
Dec 1, 2011, 8:58:50 AM12/1/11
to google-we...@googlegroups.com
Hey everyone, and thanks again for the help.

You have all given me lots of advice on security, which is something I don't have much experience on, so it's greatly appreciated. I am securing my server-side calls at the moment, and decided that as there will be only one or two admin users, it was best to add those UI elements in dynamically as otherwise everyone would have extra overhead that they didn't need.

As for the code splitting, I think that's a bit too advanced for me atm, but as my application grows it could become a possibility.

Thanks to you all again. 

Drew
Reply all
Reply to author
Forward
0 new messages