Accessing Goldberg’s Internals
From version 0.2, Goldberg provides access to some of its internal data and methods. This can be used by application developers to implement model and view security, keep custom logs or audit trails, and to assist in testing.
The Goldberg module – which forms the namespace that wraps all Goldberg’s classes – provides methods for application developers to retrieve information about Goldberg, such as the user who is currently logged in and their permissons.
The Goldberg module is loaded on server startup, and can be accessed from anywhere in your application’s controllers, models, views, in other plugins, in Rake tasks, etc.
Model and View Security
Goldberg provides comprehensive controller security, but what about security at the model and view layers? The accessors Goldberg.user and Goldberg.credentials provide information about the currently logged-in user and their security credentials, which can be used by your application.
If a user is logged in, Goldberg.user is a User object; otherwise it is nil. You can access this object’s details like any other ActiveRecord object. For example you could put the following ERB code into a view to display the name of the currently logged-in user:
<%= Goldberg.user ? Goldberg.user.name : '(not logged in)' %>
You can also use Goldberg.user in your models. For example, when retrieving records you could fetch only those for the current user:
MyModel.find(:all, :conditions => ['owner_id = ?', Goldberg.user.id])
Goldberg.credentials returns the security credentials for the current user. Unlike Goldberg.user, this is always available even if the user is not logged in (they are assigned the credentials of the public role).
Goldberg.credentials has methods to check whether the current user has the required permissions to invoke a given method or to view a content page. For example:
Goldberg.credentials.action_authorised?('some_controller', 'some_action')
That method would return true or false, depending on whether the user has the permission required to invoke the action ‘some_action’ on the controller ‘some_controller’. Similarly you can check whether a user is allowed to view a page:
Goldberg.credentials.page_authorised?('some/page/name')
You could use these methods to secure your views. For example you could selectively filter out certain parts of your ERB templates using <% if %> statements depending on whether users have certain permissions, or whether Goldberg.user indicates that they are the “owner” (whatever you define that to mean) of the information to be displayed. In fact you could design quite complex and responsive templates using helpers methods. One example might be a helper that creates secure hyperlinks: if the current user has the permission required for the link’s reference, a hyperlink is created; otherwise the link text could be greyed out or hidden.
Logging In
The code for logging into Goldberg has now been centralised in the Auth controller. This could be of assistance to developers writing functional and integration tests for their own applications, where the tests need to be run as a user who is logged in.
To log in a user programmatically, you would invoke:
Goldberg::AuthController.set_user(session, user_id)
This retrieves the user based on the provided user ID, updates the session and continues with request processing. The second argument – user_id – is optional: it can be omitted on the second and subsequent requests when a user has already been logged in. In that case, the user_id is fetched from the session.
Application Independence
You may have realised that the techniques described above would violate the independence between your application and Goldberg. You should consider the possibility that one day you might want to move away from Goldberg to some other platform. Fortunately the strategies for doing so are relatively straightforward.
If you look at RAILS_ROOT/vendor/plugins/goldberg/lib/goldberg.rb you will see that it doesn’t contain much: it’s just a central point to which Goldberg-related information is attached. You could take that module across to your new platform and simply re-write its accessors to draw information from somewhere else.
After doing that, you could just leave the name “Goldberg” in your code. But if that were distasteful to you it would be possible to rename all instances of “Goldberg.” in your code to something else. Use find and grep to find all instances in your project:
find app/ -type f | xargs grep 'Goldberg\.'
After checking that it’s safe to do so, you could change all of those occurences of “Goldberg.” to a name such as “NewName.” using sed:
find app/ -type f | xargs sed -i 's/Goldberg\./NewName\./g'
Alternatively, you could plan for this eventuality from the very beginning by making a “wrapper” module for your project. Your wrapper could use the methods of the Goldberg module, but make them available under a different namespace. For example you could make a method MyProject.user that simply calls Goldberg.user and returns the results. This approach would also give you the flexibility to alter the information coming from Goldberg before passing it to your application, in order to tailor it to your specific needs.
