Saturday, November 19. 2011
Gnome-Shell Extensions
Some weeks ago I realized that gnome-shell and all gnome3 packages were ready to be installed in my wheezy box. Cos I were (and I still am) very busy with a project I am involved, I decided not to upgrade my system at that moment. I had heard such bad comments about this new version that I felt afraid about the change (I was very comfortable with my old desktop). But I have always been a loyal gnome user so the previous weekend my new gnome3/gnome-shell environment was installed, tested and customized.
Obviously the bad comments about the new version are justified in the big differences between both versions. In my opinion plain gnome 3.0 (current version in wheezy), though very eye-candy, is very very restrictive and unproductive in its use. Lots of clicks are wasted to do the same thing you previously did in just one. This annoying fact is very related to the lost of many applets I usually managed (virtual desktop management, menus, launchers, window selector, weather,...), which made your life easier. But finally I discovered that gnome-shell introduces a new idea: gnome shell extensions. The gnome-shell uses extensions in a very similar way than firefox does but, right now, there is not a trusted gnome extension repository or a extension manager application (easy installation, auto-update and so on). But it is clear for me that it is planned for the near future.
I spent short time studying how extensions work and finally I realized they are a very good idea. From a technical view a extension consists in some JSON (configuration), JavaScript (code) and CSS (aspect) files (all HTML standards which is a good thing, at least for me). I am sure that you will can easily replace anything you did in gnome2 with a suitable extension in gnome3 but, as always, nowadays all this stuff is quite immature. One important aspect is that these extensions can also be installed in your ~/.local directory (you do not need packages from your linux distribution, although it is sure that some basic extensions will be installed by default in all distros, check this debian bug for example).
In order to configure gnome-shell and its extensions you better install gnome-tweak-tool application. But you always can do all configuration using typical gsettings command or dconf-editor application (utilities to manage the gnome configuration in general). So once I had understood new gnome-shell stuff I installed the following extensions to be comfortable with my new desktop:
Standard gnome-shell-extensions
Gnome itself has a collection of extensions (these are the ones that I think, at least, are going to be in any linux distro by default). I installed two of them:
- dock: Shows a dock-style task switcher on the right side of the screen (it replaces my typical launchers and window selectors). Next version 3.2 adds configuration properties for changing the default position and auto-hiding.
- user-theme: Loads a shell theme from ~/.themes/<name>/gnome-shell (I like to customize my desktop ).
The installation process is the following:
Get the source from GIT:
$ git clone git://git.gnome.org/gnome-shell-extensions
Go to tag gnome 3.0.2 (version of my current wheezy gnome-shell):
$ cd gnome-shell-extensions/ $ git checkout 3.0.2
Autogen, make and install them (only the two extensions):
$ ./autogen.sh --prefix=$HOME/.local --enable-extensions="user-theme dock" $ make $ make install
Right now there is a bug in glib-2.0 that it does not take into account extended schemas you have in your ~/.local/share/glib-2.0/schemas directory. So you have to copy the new schemas from there to the global directory and compile them:
$ cd ~/.local/share/glib-2.0/schemas/ $ sudo cp org.gnome.shell.extensions.dock.gschema.xml \ org.gnome.shell.extensions.user-theme.gschema.xml /usr/share/glib-2.0/schemas/ $ sudo glib-compile-schemas /usr/share/glib-2.0/schemas/
- All the themes for gnome3 (GTK, window manager or gnome-shell itself) can be download from gnome-look.org. They are installed as always inside ~/.themes and ~/.icons directories. Use gnome-tweak-tool to change any theme.
gnome-shell-weather-extension
Another applet I used to add to my gnome2 panel was the weather applet. An equivalent extension is the gnome-shell-weather-extension done by Simon Legner but it nowadays does not have several locations like the old applet . The installation is more or less the same:
Clone the repository with git (branch 3.0):
$ git clone -b gnome3.0 https://github.com/simon04/gnome-shell-extension-weather
Install:
$ cd gnome-shell-extension-weather/ $ ./autogen.sh --prefix=$HOME/.local $ make $ make install
Because of the commented glib2 bug you need to include the schemas globally:
$ cd ~/.local/share/glib-2.0/schemas $ sudo cp org.gnome.shell.extensions.weather.gschema.xml /usr/share/glib-2.0/schemas/ $ sudo glib-compile-schemas /usr/share/glib-2.0/schemas/
Then you need to set the city for the weather, in my case Madrid. I did it via gsettings (you can also use dconf-editor):
$ gsettings set org.gnome.shell.extensions.weather woeid "'766273'"
gnome-shell-workspace-indicator
Finally workspaces in default gnome3 needs too many clicks for me (I change working workspace very often to waste time doing that). So I installed another extension that adds workspace selection in gnome-shell toolbar. This extension has been incorporated to default gnome-shell extensions in latest version 3.2 (but it does not exist in the 3.0.2/wheezy version I installed in the first point).
The installation is pretty the same:
Clone the sources:
$ git clone git://github.com/erick2red/shell-extensions.git
Generate and install:
$ cd shell-extensions/ $ ./autogen.sh --prefix=$HOME/.local --enable-extensions="workspace-indicator" $ make $ make install
Installation of the schemas:
$ cd schemas/ $ sudo cp org.gnome.shell.extensions.workspace-indicator.gschema.xml \ /usr/share/glib-2.0/schemas/ $ sudo glib-compile-schemas /usr/share/glib-2.0/schemas/
I prefer wide indicator (with wide indicator you see Workspace 1 instead of the concise 1 you get with default configuration):
$ gettings set org.gnome.shell.extensions.workspace-indicator \ wide-indicator true
I tried to be comfortable but with the least number of extensions. Think you have to re-add them every time you upgrade gnome-shell version (until there was a better solution: a gnome extension manager infraestructure, distro provided extensions or whatever). My desktop currently has the following aspect.
I have written this entry because, as I commented before, I will need to update my extensions when a new version of the gnome-shell arrives (3.2 for example). I hope that shortly some extension management will come to gnome3 and all this stuff will be automatically done (as firefox does), but right now extensions need to be installed manually. There are a lot of them scattered throughout the internet and there are also several links which comment the must-have ones (for example this, this or this). Installation can be independent of the linux distribution (although some basic extensions will come by default for sure). I have only installed four extensions in my desktop: user-theme support, dock, weather and workspace. You can enable or disable extensions and customize them via gnome-tweak-tool (coarse-grained changes) and gsettings or dconf-editor (fine-grained configuration).
Finally I got the conclusion that gnome3 and its extensions are a brilliant idea. I think that, with a proper management and repository, its future is awesome but right now gnome3 falls a bit short. In my opinion that is the reason for all the bad comments and the negative impression of many users.
Long life gnome3!
Wednesday, November 9. 2011
Certificate Security in JavaEE - Standard Solution (Glassfish)
Today I am going to present the last entry of the series about certificate security in a JavaEE application. If you remember the first post dealt with the environment setup (not very interesting in terms of development but a nice guide about a quick CA and secure server installation) and the second one commented custom security using client certificates (the application itself mapped the certificates and real users and groups). This last entry will present client certificates authentication but using standard JavaEE security.
JavaEE uses security based on roles, each user will have some roles, and depending these roles he can or cannot perform the specific application actions. Talking about what can be protected JavaEE adds security to two types of resources in a direct way: any web resource (pages, servlets,...) and Enterprise Java Beans (EJB) (the whole bean and/or specific methods of the bean). The security can be mapped via the deployment descriptor, web.xml in case of the web resources (security-constraint directive) and ejb-jar.xml in case of EJBs (method-permission and so on), or using annotations (@DeclareRoles, @RolesAllowed, @PermitAll or @DenyAll). The JavaEE API also offers methods to know the roles of a user and perform a programmatic security (isUserInRole in HttpServletRequest and isCallerInRole in EJBContext). So the idea is pretty clear, based on the roles of the user the application has to manage its own security which can be declarative (assembler files or annotations), programmatic (API) or both.
So now that JavaEE security is understood we need to know how the roles are assigned to a specific user. Basically the roles are defined for the application (again assembler file descriptors or annotations) and then they are mapped against users and groups inside some repository. JavaEE manages the concept of realms, which are stores for users and groups associated to the container. The containers perform the mapping between them and the application roles via a proprietary file descriptor (glassfish-web.xml, weblogic.xml,...) and/or using the container management console (case of IBM WebSphere). Each application server manages the realms in its own way, they can be more or less powerful (for example weblogic has clearly a much more customizable realms than glassfish or tomcat).
The last part of theory which needs to be commented is the login issue. Once the JavaEE application has added role restrictions it needs to establish a login method. The standard configures the login inside the login-config part of the web.xml. It permits the following methods for authentication: NONE, BASIC, DIGEST, FORM or CLIENT-CERT. This login is also associated to a realm in the container. So now it is clear, when an application establishes JavaEE security, it defines a realm, a login method and different roles; the users who try to access the application will need to login first and, in this process, they get all the groups from the selected realm (in JavaEE jargon the user and groups obtained from the realm are called principals); these groups are mapped against the app roles; finally the roles are used to implement security (declarative or programmatic) inside the application. As you see the circle is now closed.
JavaEE is sometimes quite overelaborated, but be sure that the ideas behind it are very very simple. You can read the JavaEE tutorial (current version 6) for further information about its security model.
Going back to our particular case of client certificates, it is clear that CLIENT-CERT authentication login method has to be selected. And, as it is a standard defined login method, everything should work smoothly, but Glassfish is not the case. What I want you to have in mind is that now all this stuff is in the hands of your container, we are talking about JavaEE, therefore the way login and mapping are handled does not depend on the application but on the container itself.
I chose glassfish v3 as my application server for this series and it has a special certificate realm, this realm is always used when CLIENT-CERT login is specified for an application (this part is not configurable). By default it only gets the subject of the certificate and sets it as the user principal, but nothing else, so forget about ldap, groups or whatever. Nevertheless glassfish joins realm implementations to a JAAS (Java Authentication and Authorization Service) login module context. A JAAS context can specify several (and custom) login modules, this way a custom certificate login module can be implemented to get the user from the certificate and match him to a user in the company repository. This way I defined a new login module inside the domains/domain1/config/login.conf:
certLdapRealm { sample.loginmodule.CertLdapLoginModule required realm=ldap; };
I created a CertLdapLoginModule.java which extends AppservCertificateLoginModule, an abstract class that glassfish explicitly provides to implement custom certificate login modules. My new class only has to implement the authenticateUser method, in here, my idea is clear: getting the user from the subject (same as in custom security, the user login is the CN part of the certificate subject) and querying the ldap with it in order to obtain the user and groups.
I first thought reusing the glassfish LDAPRealm for all the ldap stuff but this realm has all methods declared as private and I could not find a way of searching the user. The class is declared final so it cannot be extended either. Finally I copied the class code and a new LDAPRealm.java was created. It is almost the same code except the method findAndBind, which now receives a new boolean parameter checkPassword, if it is false no bind is performed and the user and groups are retrieved without password.
You have noticed that the certLdapRealm JAAS definition defines a realm option parameter, this parameter marks the realm which implements the new LDAPRealm class. The code inside my custom login class (autheticateUser method) is the following:
protected void authenticateUser() throws LoginException { String realm = (String) _options.get(REALM_OPTION); if (realm == null) { throw new LoginException( "LoginModule has not 'realm' option to get the LDAP realm!"); } try { // get the user from the certificate LdapName name = new LdapName(this.getX500Principal().getName()); String certName = name.getRdn(name.size() - 1).getValue().toString(); // get the realm LDAPRealm ldap = (LDAPRealm) Realm.getInstance(realm); if (ldap == null) { throw new LoginException("Realm'" + realm + "' does not exists!"); } String[] grpList = ldap.findAndBind(certName, null, false); // add the short user as a user principal // LoginContextDriver sets the cert subject as the name of the user // this let the user to set roles based on user (uid) names getSubject().getPrincipals().add(new PrincipalImpl(certName)); // add groups => commit sets them as group principals commitUserAuthentication(grpList); } catch (Exception e) { throw new LoginException(e.getMessage()); } }
The method gets the LDAPRealm using the specified option. The CN part of the certificate subject is read in order to query the ldap. The custom findAndBind method is used with false argument (do not bind the user). If everything goes well the groups that have been returned are passed to be transformed into principals. Check that the user himself is added as a principal before, this is done cos the certificate realm uses the complete DN as username (now both ways, complete DN or just the UID part can be used in the role mapping file).
Finally the certificate realm inside glassfish has to be configured to use the new JAAS module. This was done directly in the domain.xml file (asadmin can also be used for this configuration):
<auth-realm name="certificate" classname="com.sun.enterprise.security.auth.realm.certificate.CertificateRealm"> <property name="jaas-context" value="certLdapRealm"></property> <property name="assign-groups" value="allusers"></property> </auth-realm>
The jaas-context property specifies the JAAS context to be used (it was set to certLdapRealm). The other property assign-groups are groups that are directly assigned to any user who successfully logs in this realm (they are used in web.xml for specifying any authenticated user).
Finally the LDAPRealm (used inside the custom login module) has to be configured in glassfish too:
<auth-realm name="ldap" classname="sample.realm.LDAPRealm"> <property name="directory" value="ldap://debian.demo.kvm:389"></property> <property name="base-dn" value="dc=demo,dc=kvm"></property> <property name="jaas-context" value="myLdapRealm"></property> <property name="search-bind-dn" value="cn=admin,dc=demo,dc=kvm"></property> <property name="search-bind-password" value="****"></property> <property name="assign-groups" value="allusers"></property> </auth-realm>
This is a normal configuration for a glassfish LDAPRealm (except that my class is used instead of the glassfish default). Please check that the realm name is ldap, exactly the same name which is passed to my certLdapRealm JAAS context in the login.conf file. The extra realm and login module classes were packaged into a jar and placed inside domains/domain1/lib directory (see this article for more information about custom realms and login modules in glassfish).
I know that all of this is quite confusing, so I am going to repeat the idea. The default certificate realm now depends on a custom certLdapRealm JAAS context. This context executes a custom CertLdapLoginModule which uses another realm ldap (custom LDAPRealm but with minimal differences from the glassfish default) to search the user and his groups in the LDAP repository. In my opinion glassfish realms and login modules are too dependent on each other, they always generate cross references, and that generates some mess.
So now everything is correctly configured to deploy a JavaEE security application which uses client certificates. I deployed the same application that was used in the custom security entry, but now it does not need all ldap stuff so it is almost an empty app (only some facelets pages and little helper Java classes). The interesting part of this application is inside the descriptor (web.xml) file. It defines the following constraint:
<security-constraint> <display-name>CertSecurityJavaEE constraint</display-name> <web-resource-collection> <web-resource-name>Servlet Application</web-resource-name> <url-pattern>/faces/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>allusers</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint>
All faces pages (pattern /faces/*) are declared inside the constraint. The role allusers is declared as needed to access the application (any user authenticated in the realm). Besides the constraint declares the data as confidential, this means that the application has to be used securely (over HTTPS). The login part is as follows:
<login-config> <auth-method>CLIENT-CERT</auth-method> <realm-name>ldap</realm-name> <form-login-config> <form-login-page>/faces/login.xhtml</form-login-page> <form-error-page>/faces/login.xhtml</form-error-page> </form-login-config> </login-config>
I declared CLIENT-CERT which means the user needs to present a certificate to get access (as I said glassfish uses the certificate realm for this configuration, and all the previous configuration comes into stage). And finally some roles are defined for the application:
<security-role> <description>Users Role</description> <role-name>allusers</role-name> </security-role> <security-role> <description>StaticGroup1 Role</description> <role-name>StaticGroup1</role-name> </security-role> <security-role> <description>DynGroupPreSales Role</description> <role-name>DynGroupPreSales</role-name> </security-role> <security-role> <description>SampleClient1 Role</description> <role-name>SampleClient1</role-name> </security-role>
The application manages four roles:
- allusers: All the users of the application (any authenticated user).
- StaticGroup1: The static group of the ldap (I used it in the previous entry).
- DynGroupPreSales: The dynamic group of the ldap (I also used it before).
- SampleClient1: This is an example user role, only the SampleClient1 is part of this role. I added this role to check if my login module handles user short login name (UID in LDAP) correctly.
As I said glassfish used a specific glassfish-web.xml descriptor file to map the roles against the users and groups in the realm, here it is my mapping:
<security-role-mapping> <role-name>allusers</role-name> <group-name>allusers</group-name> </security-role-mapping> <security-role-mapping> <role-name>StaticGroup1</role-name> <group-name>StaticGroup1</group-name> </security-role-mapping> <security-role-mapping> <role-name>DynGroupPreSales</role-name> <group-name>DynGroupPreSales</group-name> </security-role-mapping> <security-role-mapping> <role-name>SampleClient1</role-name> <principal-name>SampleClient1</principal-name> </security-role-mapping>
Basically I mapped all roles to the so-called LDAP group (remember allusers is a nonexistent ldap group, which is automatically added by the realm when a user is authenticated, it was defined in the assign-groups property of both realms) except SampleClient1 which is mapped against the same username (I used the short CN name, the one that is added by my custom login module).
Now the application is ready, but please think about it, how does it work? When the user access to the application he needs to present a certificate (it is compulsory) and there is no other choice. As you can imagine this is too much restrictive in common situations. In other JavaEE containers a fallback authentication method can be configured (CLIENT-CERT,FORM for example in weblogic) but not in glassfish. So I decided to deploy the same application twice, one with CLIENT-CERT authentication (/CertSecurityJavaEE-cert context) and the other with FORM (/CertSecurityJavaEE context). If you check the previously presented login part of the web.xml the ldap realm is specified (remember that glassfish uses certificate realm for CLIENT-CERT authorization no matter the configuration, so this ldap realm is only used when FORM authentication is selected). In order to use my custom LDAPRealm class here I needed to implement a custom LDAPLoginModule.java that extends glassfish default (because the damned cross references), but you can ignore this, it is too confusing even for me who implemented the solution.
The CLIENT-CERT option makes unnecessary the client authentication configuration we did in the secure listener of glassfish (check the first entry of this series). If CLIENT-CERT authentication method is established for an application the app server automatically requests a client certificate for its context in the secure port. So I unchecked this option and now a user without certificate is able to access the FORM defined application through the same secure port (the other /CertSecurityJavaEE context). Besides an HTML error page for 401 error code (Unauthorized) was configured for the application. What does it mean? Now a user who presents a certificate in /CertSecurityJavaEE-cert but has no mapped user in the LDAP server will receive a custom 401 error page, this page will show a link against the FORM authenticated application. This is configured (standard way) in the web.xml file.
<error-page> <error-code>401</error-code> <location>/resources/errorpages/401.html</location> </error-page>
Here it is the video. Now when I access to the certificate application (/CertSecurityJavaEE-cert) a certificate is requested. Same as before if I select the revoked certificate (03) firefox requests me to choose another one because it is revoked, if I pick up the valid one (02) I just enter as SampleClient1 (see all the roles are granted and the long certificate subject is used as username). Now I cannot logout cos once you have selected a certificate for a site the browser uses always it for this site (it is the same case than in custom security). Then I clear my sessions in firefox (this logs me out to try again) and I try to enter with a new certificate, created for SampleClient3 with serial number 05 but without a mapped real user, so this time my login module fails to match a user and the 401 page is reached. There I can click the presented link and I access the non-certificate (/CertSecurityJavaEE) application. Finally I log in using SampleClient2 (remember this user has a revoked certificate but he is a valid user in the LDAP server). He has no role assigned as expected and now the user name is the short one.
The moral for standard JavaEE certificate login is that it depends on the container implementation, the application just needs to configure CLIENT-CERT authentication. As you see glassfish realms (and the certificate one particularly) are quite confusing, there is a lot of mess between realms and login modules and it is specially painful using or extending its default classes (I do not know why but they have a lot of private methods and they are usually declared as final). The best I could do was implementing a custom login module which was associated to the certificate realm, this login class performs the mapping between certificate and user (groups included). Besides the application was deployed twice, one requests client certificates and the other uses typical username and password login, this way users without a certificate have a less secure but functional way to login. For this entry two projects were developed, the library project with realms and login modules and the Web Application project. My personal conclusion is that all of this is so particular for glassfish that a different entry like this one is needed for every JavaEE container.
You win some, you lose some. Cheerio!
Comments