Integrating with Seam 3 Security would require a specific security service, which does not really exist.
We had started a prototype some time ago but never finished because Seam 3 was more or less abandoned:
public class Seam3SecurityService extends AbstractSecurityService {
// private static final Logger log = Logger.getLogger(Seam3SecurityService.class);
@Inject
private CDIServiceContext serviceContext;
@Inject
private Identity identity;
@Inject
private CredentialsImpl seamCredentials;
public void configure(Map<String, String> params) {
}
public void login(Object credentials) throws SecurityServiceException {
String[] decoded = decodeBase64Credentials(credentials);
serviceContext.setLogin(true);
// // Unauthenticate if username has changed (otherwise the previous session/principal is reused)
// if (identity.isLoggedIn() && !decoded[0].equals(identity.getUser().getId())) {
// try {
// Method method = identity.getClass().getDeclaredMethod("unAuthenticate");
// method.setAccessible(true);
// method.invoke(identity);
// } catch (Exception e) {
// log.error(e, "Could not call unAuthenticate method on: %s", identity.getClass());
// }
// }
seamCredentials.setUsername(decoded[0]);
seamCredentials.setPassword(decoded[1]);
String ok = identity.login();
if (ok == null)
throw SecurityServiceException.newInvalidCredentialsException("User authentication failed");
}
public Object authorize(AbstractSecurityContext context) throws Exception {
startAuthorization(context);
if (context.getDestination().isSecured()) {
if (!identity.isLoggedIn()) {
// TODO: Session expiration detection...
// throw SecurityServiceException.newSessionExpiredException("Session expired");
throw SecurityServiceException.newNotLoggedInException("User not logged in");
}
boolean accessDenied = true;
for (String role : context.getDestination().getRoles()) {
if (identity.inGroup(role, "ROLE")) {
accessDenied = false;
break;
}
}
if (accessDenied)
throw SecurityServiceException.newAccessDeniedException("User not in required role");
}
try {
return endAuthorization(context);
} catch (InvocationTargetException e) {
for (Throwable t = e; t != null; t = t.getCause()) {
// If destination is not secured...
if (t instanceof NotLoggedInException)
throw SecurityServiceException.newNotLoggedInException("User not logged in");
// Don't create a dependency to javax.ejb in SecurityService...
if (t instanceof SecurityException ||
t instanceof AuthorizationException ||
"javax.ejb.EJBAccessException".equals(t.getClass().getName()))
throw SecurityServiceException.newAccessDeniedException(t.getMessage());
}
throw e;
}
}
public void logout() throws SecurityServiceException {
if (identity.isLoggedIn())
identity.logout();
}
}
package org.jboss.seam.security {
import flash.events.Event;
import flash.utils.Dictionary;
import flash.utils.flash_proxy;
import mx.collections.ArrayCollection;
import mx.collections.ItemResponder;
import mx.core.Application;
import mx.events.PropertyChangeEvent;
import mx.messaging.events.ChannelFaultEvent;
import mx.messaging.messages.ErrorMessage;
import mx.rpc.AsyncToken;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.utils.object_proxy;
import org.granite.events.SecurityEvent;
import org.granite.tide.BaseContext;
import org.granite.tide.Component;
import org.granite.tide.IEntity;
import org.granite.tide.IIdentity;
import org.granite.tide.ITideResponder;
import org.granite.tide.Tide;
import org.granite.tide.events.TideContextEvent;
import org.granite.tide.events.TideFaultEvent;
import org.granite.tide.events.TideResultEvent;
use namespace flash_proxy;
use namespace object_proxy;
[Bindable]
/**
* Implementation of the identity component for Seam services.<br/>
* Integrates with the server-side identity component of Seam.<br/>
* <br/>
* The basic way of using it is by populating username/password and calling login :<br/>
* <pre>
* identity.username = 'john';
* identity.password = 'doe';
* identity.login();
* </pre>
*
* @author William DRAI
*/
[RemoteClass(alias="org.jboss.seam.security.Identity")]
public class Identity extends Component implements IIdentity {
public override function meta_init(componentName:String, context:BaseContext):void {
super.meta_init(componentName, context);
context.addContextEventListener(Tide.LOGIN, loginSuccessHandler);
}
public function set context(context:BaseContext):void {
_context = context;
}
public function get meta_credentialsClassName():String {
return "org.jboss.seam.security.CredentialsImpl";
}
/**
* Logged in
*/
public function get loggedIn():Boolean {
return super.getProperty("loggedIn");
}
/**
* Logged in
*/
public function set loggedIn(loggedIn:Boolean):void {
setInternalProperty("loggedIn", loggedIn);
if (!loggedIn)
_context.meta_logout(this);
}
/**
* Triggers a remote call to check is user is currently logged in
* Can be used at application startup to handle browser refresh cases
*
* @param resultHandler optional result handler
* @param faultHandler optional fault handler
*/
public function isLoggedIn(resultHandler:Function = null, faultHandler:Function = null):void {
var l:Boolean = loggedIn;
var u:String = _context.byType(Credentials).username;
_context.meta_isLoggedIn(this, resultHandler, faultHandler);
}
/**
* Triggers a login request
*
* @param resultHandler optional result handler
* @param faultHandler optional fault handler
*/
public function login(resultHandler:Function = null, faultHandler:Function = null):void {
var l:Boolean = loggedIn; // Force evaluation of loggedIn state
var credentials:Credentials = _context.byType(Credentials) as Credentials;
credentials.meta_login(this, resultHandler, faultHandler);
}
private function loginSuccessHandler(event:TideContextEvent):void {
initSecurityCache();
}
/**
* Triggers a logout request
*/
public function logout():void {
loggedIn = false;
_context.byType(Credentials).username = null;
clearSecurityCache();
// Must be at the end, because it resets the current identity instance
// Not necessary, called by loggedIn = false
// _context.meta_logout(this);
}
private var _groupsCache:Object = new Object();
/**
* Check role permission for the specified role
*
* @param roleName role name
* @param resultHandler result handler
* @param faultHandler fault handler
* @return true is role allowed
*/
[Bindable("groupChanged")]
public function inGroup(groupName:String, resultHandler:Function = null, faultHandler:Function = null):Boolean {
var has:* = _groupsCache[groupName];
if (has === undefined) {
if (loggedIn) {
var responder:TideGroupResponder = new TideGroupResponder(groupResultHandler, groupFaultHandler, groupName);
responder.addHandlers(resultHandler, faultHandler);
_context.meta_callComponent(this, "inGroup", [groupName, "ROLE", responder], false);
_groupsCache[groupName] = responder;
}
return false;
}
if (has is TideGroupResponder) {
has.addHandlers(resultHandler, faultHandler);
return false;
}
if (resultHandler != null) {
var event:TideResultEvent = new TideResultEvent(TideResultEvent.RESULT, _context, false, false, null, has);
resultHandler(event, groupName);
}
return (has as Boolean);
}
private function groupResultHandler(event:TideResultEvent, groupName:String):void {
_groupsCache[groupName] = event.result as Boolean;
dispatchEvent(new Event("groupChanged"));
}
private function groupFaultHandler(event:TideFaultEvent, groupName:String):void {
delete _groupsCache[groupName];
}
private var _permissionsCache:Dictionary = new Dictionary(true);
/**
* Check permission for the specified target and action
*
* @param target target object
* @param action requested action
* @param resultHandler result handler
* @param faultHandler fault handler
* @return true is permission granted
*/
[Bindable("permissionChanged")]
public function hasPermission(target:Object, action:String, resultHandler:Function = null, faultHandler:Function = null):Boolean {
var cache:Object = _permissionsCache[target];
if (cache == null || (cache && cache[action] === undefined)) {
if (loggedIn) {
var responder:TidePermissionResponder = new TidePermissionResponder(permissionResultHandler, permissionFaultHandler, target, action);
responder.addHandlers(resultHandler, faultHandler);
_context.meta_callComponent(this, "hasPermission", [target, action, responder], false);
if (cache == null) {
cache = new Object();
_permissionsCache[target] = cache;
}
cache[action] = responder;
}
return false;
}
if (cache[action] is TidePermissionResponder) {
cache[action].addHandlers(resultHandler, faultHandler);
return false;
}
if (resultHandler != null) {
var event:TideResultEvent = new TideResultEvent(TideResultEvent.RESULT, _context, false, false, null, cache[action]);
resultHandler(event, target, action);
}
return (cache[action] as Boolean);
}
private function permissionResultHandler(event:TideResultEvent, target:Object, action:String):void {
_permissionsCache[target][action] = event.result as Boolean;
dispatchEvent(new Event("permissionChanged"));
}
private function permissionFaultHandler(event:TideFaultEvent, target:Object, action:String):void {
delete _permissionsCache[target];
}
private function initSecurityCache():void {
dispatchEvent(new Event("groupChanged"));
dispatchEvent(new Event("permissionChanged"));
}
/**
* Clear the security cache
*/
public function clearSecurityCache():void {
_groupsCache = new Object();
_permissionsCache = new Dictionary(true);
}
}
}
import flash.utils.Dictionary;
import org.granite.tide.ITideResponder;
import org.granite.tide.events.TideResultEvent;
import org.granite.tide.events.TideFaultEvent;
class TideGroupResponder implements ITideResponder {
private var _resultHandlers:Array = new Array();
private var _faultHandlers:Array = new Array();
private var _groupName:String;
public function TideGroupResponder(resultHandler:Function, faultHandler:Function, groupName:String):void {
if (resultHandler != null)
_resultHandlers.push(resultHandler);
if (faultHandler != null)
_faultHandlers.push(faultHandler);
_groupName = groupName;
}
public function addHandlers(resultHandler:Function = null, faultHandler:Function = null):void {
if (resultHandler != null)
_resultHandlers.push(resultHandler);
if (faultHandler != null)
_faultHandlers.push(faultHandler);
}
public function result(event:TideResultEvent):void {
for each (var resultHandler:Function in _resultHandlers)
resultHandler(event, _groupName);
}
public function fault(event:TideFaultEvent):void {
for each (var faultHandler:Function in _faultHandlers)
faultHandler(event, _groupName);
}
}
class TidePermissionResponder implements ITideResponder {
private var _resultHandlers:Array = new Array();
private var _faultHandlers:Array = new Array();
private var _target:Object;
private var _action:String;
public function TidePermissionResponder(resultHandler:Function, faultHandler:Function, target:Object, action:String):void {
if (resultHandler != null)
_resultHandlers.push(resultHandler);
if (faultHandler != null)
_faultHandlers.push(faultHandler);
_target = target;
_action = action;
}
public function addHandlers(resultHandler:Function = null, faultHandler:Function = null):void {
if (resultHandler != null)
_resultHandlers.push(resultHandler);
if (faultHandler != null)
_faultHandlers.push(faultHandler);
}
public function result(event:TideResultEvent):void {
for each (var resultHandler:Function in _resultHandlers)
resultHandler(event, _target, _action);
}
public function fault(event:TideFaultEvent):void {
for each (var faultHandler:Function in _faultHandlers)
faultHandler(event, _target, _action);
}
}
Don't hesitate to send a pull request if you can make it work.