Tapestry覆盖Authenticator

huangapple go评论84阅读模式
英文:

Tapestry override Authenticator

问题

我正在尝试为 tapestry-security (org.tynamo.security) 使用自定义的认证器。

我有一个自定义的认证器:

public class EnvironmentalRealmAuthenticator extends ModularRealmAuthenticator

在我的模块中,我覆盖了 Tapestry 的默认认证器 (ModularRealmAuthenticator):

public static void bind(final ServiceBinder binder) {
    binder.bind(Authenticator.class, EnvironmentalRealmAuthenticator.class).withId("EnvironmentalRealmAuthenticator");
}

@Contribute(ServiceOverride.class)
public static void setupOverrides(final MappedConfiguration<Class, Object> configuration, @Local final Authenticator override) {
    configuration.add(Authenticator.class, override);
}

然而,这会导致缓存在注销时不被清除 - 我怀疑这是由 Shiro 的 DefaultSecurityManager 检测认证器是否监听注销的方式引起的:

Authenticator authc = getAuthenticator();
if (authc instanceof LogoutAware) {
    ((LogoutAware) authc).onLogout(principals);
}

由于 EnvironmentalRealmAuthenticator 被绑定为 Tapestry 服务,它最初被注入为代理,因此 authc instanceof LogoutAware 得到 false - 这就是为什么在 Tynamo 的 SecurityModule 中以不同的方式绑定默认的 ModularRealmAuthenticator 的原因:

binder.bind(ModularRealmAuthenticator.class);

然而,当我尝试以这种方式覆盖我的 EnvironmentalRealmAuthenticator 时:

binder.bind(EnvironmentalRealmAuthenticator.class).withId("EnvironmentalRealmAuthenticator");

会导致以下异常:

Caused by: java.lang.IllegalStateException: Construction of service 'ServiceOverride' has failed due to recursion: the service depends on itself in some way. Please check org.apache.tapestry5.ioc.internal.services.ServiceOverrideImpl(Map) (at ServiceOverrideImpl.java:31) via org.apache.tapestry5.ioc.modules.TapestryIOCModule.bind(ServiceBinder) (at TapestryIOCModule.java:52) for references to another service that is itself dependent on service 'ServiceOverride'.
英文:

I am trying to use a custom authenticator for tapestry-security (org.tynamo.security).

I have a custom authenticator

public class EnvironmentalRealmAuthenticator extends ModularRealmAuthenticator

And in my module I override the default authenticator of Tapestry (ModularRealmAuthenticator):

public static void bind(final ServiceBinder binder) {

    binder.bind(Authenticator.class, EnvironmentalRealmAuthenticator.class).withId(&quot;EnvironmentalRealmAuthenticator&quot;);
}

@Contribute(ServiceOverride.class)
public static void setupOverrides(final MappedConfiguration&lt;Class, Object&gt; configuration, @Local final Authenticator override) {
    configuration.add(Authenticator.class, override);
}

However, this causes the cache to not be cleared on logout - I have the suspicion that this is caused by the way the DefaultSecurityManager of Shiro detects if the authenticator listens to logouts:

Authenticator authc = getAuthenticator();
if (authc instanceof LogoutAware) {
    ((LogoutAware) authc).onLogout(principals);
}

As the EnvironmentalRealmAuthenticator is bound as a Tapestry service, it is initially injected as a proxy and hence authc instanceof LogoutAware yields false - that's why the default ModularRealmAuthenticator is bound in a different way in the SecurityModule of Tynamo:

// TYNAMO-155 It&#39;s not enough to identify ModularRealmAuthenticator by it&#39;s Authenticator interface only
// because Shiro tests if the object is an instanceof LogoutAware to call logout handlers
binder.bind(ModularRealmAuthenticator.class);

However, when I try to override my EnvironmentalRealmAuthenticator that way

binder.bind(EnvironmentalRealmAuthenticator.class).withId(&quot;EnvironmentalRealmAuthenticator&quot;);

this results in the following exception:

> Caused by: java.lang.IllegalStateException: Construction of service 'ServiceOverride' has failed due to recursion: the service depends on itself in some way. Please check org.apache.tapestry5.ioc.internal.services.ServiceOverrideImpl(Map) (at ServiceOverrideImpl.java:31) via org.apache.tapestry5.ioc.modules.TapestryIOCModule.bind(ServiceBinder) (at TapestryIOCModule.java:52) for references to another service that is itself dependent on service 'ServiceOverride'.

答案1

得分: 1

我无法确定,在没有看到导致异常的setupOverrides方法的最终版本之前。

但是,你尝试过这样吗:

public static void bind(final ServiceBinder binder) {

    binder.bind(EnvironmentalRealmAuthenticator.class);
}

@Contribute(ServiceOverride.class)
public static void setupOverrides(final MappedConfiguration<Class, Object> configuration, EnvironmentalRealmAuthenticator override) {
    configuration.add(Authenticator.class, override);
}
英文:

I can't be sure without seeing the final version of your setupOverrides method that caused that exception.

But, have you tried this:

public static void bind(final ServiceBinder binder) {

    binder.bind(EnvironmentalRealmAuthenticator.class);
}

@Contribute(ServiceOverride.class)
public static void setupOverrides(final MappedConfiguration&lt;Class, Object&gt; configuration, EnvironmentalRealmAuthenticator override) {
    configuration.add(Authenticator.class, override);
}

答案2

得分: 1

我似乎找到了一个(相当巧妙的)方法。而不是覆盖 Authenticator 本身,我覆盖了 WebSecuritymanager

public static void bind(final ServiceBinder binder) {
    binder.bind(EnvironmentalRealmAuthenticator.class).withId("EnvironmentalRealmAuthenticator");
    binder.bind(WebSecurityManager.class, EnvironmentalSecurityManager.class).withId("EnvironmentalSecurityManager");
}

@Contribute(ServiceOverride.class)
public static void setupOverrides(final MappedConfiguration<Class, Object> configuration, @Local final WebSecurityManager override) {
    configuration.add(WebSecurityManager.class, override);
}

这样,我就不必将 EnvironmentalRealmAuthenticator 与其接口绑定起来。为了能够识别新的 Authenticator,我对模块进行了注解:

@Marker(Primary.class)

然后,EnvironmentalSecurityManager 的实现如下所示:

/**
 * 用于正确(且唯一)地标识 Authenticator(无需覆盖它)
 */
public class EnvironmentalSecurityManager extends TapestryRealmSecurityManager {

    private final Logger logger = LoggerFactory.getLogger(EnvironmentalSecurityManager.class);

    /**
     * 注意 @Primary 注解,用于标识 EnvironmentalRealmAuthenticator
     */
    public EnvironmentalSecurityManager(final @Primary Authenticator authenticator, final SubjectFactory subjectFactory, final RememberMeManager rememberMeManager, final Collection<Realm> realms) {

        super(authenticator, subjectFactory, rememberMeManager, realms);
        logger.debug("Created EnvironmentalSecurityManager - class of authenticator is {}", authenticator.getClass());
    }
}

这样,我可以确保正确的 Authenticator 被使用,而无需实际覆盖它。

英文:

I seem to have found a (rather hacky) way. Instead of overriding the Authenticator itself, I override the WebSecuritymanager instead:

public static void bind(final ServiceBinder binder) {
    binder.bind(EnvironmentalRealmAuthenticator.class).withId(&quot;EnvironmentalRealmAuthenticator&quot;);
    binder.bind(WebSecurityManager.class, EnvironmentalSecurityManager.class).withId(&quot;EnvironmentalSecurityManager&quot;);
}

@Contribute(ServiceOverride.class)
public static void setupOverrides(final MappedConfiguration&lt;Class, Object&gt; configuration, @Local final WebSecurityManager override) {
    configuration.add(WebSecurityManager.class, override);
}

That way I don't have to bind the EnvironmentalRealmAuthenticator with its interface. In order to be able to identify the new Authenticator I annotated the module:

@Marker(Primary.class)

The implmentation of the EnvironmentalSecurityManager then looks like this:

/**
 * Used to properly (and uniquely) identify the authenticator (without having to override it)
 */
public class EnvironmentalSecurityManager extends TapestryRealmSecurityManager {

    private final Logger logger = LoggerFactory.getLogger(EnvironmentalSecurityManager.class);

    /**
     * Mind the @Primary annotation, used to identify the EnvironmentalRealmAuthenticator
     */
    public EnvironmentalSecurityManager(final @Primary Authenticator authenticator, final SubjectFactory subjectFactory, final RememberMeManager rememberMeManager, final Collection&lt;Realm&gt; realms) {

        super(authenticator, subjectFactory, rememberMeManager, realms);
        logger.debug(&quot;Created EnvironmentalSecurityManager - class of authenticator is {}&quot;, authenticator.getClass());
    }
}

That way I can guarantee that the correct Authenticator is used without actually having to override it.

huangapple
  • 本文由 发表于 2020年10月27日 23:06:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/64557263.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定