This is what I had to write to achieve this. Perhaps the developers of
Shiro might consider finding a way to make it easier?
Stephen
public final class ShiroSecurityEnvironmentLoader extends
EnvironmentLoaderListener {
@Override
protected WebEnvironment createEnvironment(ServletContext servletContext) {
ShiroWebEnvironment environment = new ShiroWebEnvironment();
environment.setServletContext(servletContext);
String configLocations =
StringUtils.trimToNull(servletContext.getInitParameter(CONFIG_LOCATIONS_PARAM));
if (configLocations != null) {
environment.setConfigLocations(configLocations);
}
environment.init();
return environment;
}
//-------------------------------------------------------------------------
/**
* Apache Shiro web environment that re-uses the static manager.
*/
private final class ShiroWebEnvironment extends IniWebEnvironment {
@Override
protected WebSecurityManager createWebSecurityManager() {
ShiroFactory factory = new ShiroFactory();
factory.setIni(getIni());
WebSecurityManager wsm = (WebSecurityManager) factory.getInstance();
Map<String, ?> beans = factory.getBeans();
if (!CollectionUtils.isEmpty(beans)) {
this.objects.putAll(beans);
}
return wsm;
}
}
//-------------------------------------------------------------------------
/**
* Apache Shiro factory that re-uses the static manager.
*/
private class ShiroFactory extends WebIniSecurityManagerFactory {
@Override
protected SecurityManager createDefaultInstance() {
try {
SecurityManager sm = SecurityUtils.getSecurityManager();
if (sm instanceof WebSecurityManager) {
return sm;
}
return super.createDefaultInstance();
} catch (UnavailableSecurityManagerException ex) {
return super.createDefaultInstance();
}
}
}
}
On 14 March 2014 16:29, Dominic Farr <[email protected]> wrote:
> I agree constructor over setter every time; but that is another
> conversation.
>
> If you are using EmbeddedJetty which configures shiro's
> EnvironmentLoaderListener, I would suggest replacing, or encapsulating the
> shiro EnvironmentLoaderListener with your own ServletContextListener and
> inject your SecurityManager instance into that.
>
> I've done something similar with a Dropwizard project that uses an jetty and
> it works nicely.
>
> -d
>
>
>
>
> On 14 March 2014 16:15, Stephen Colebourne <[email protected]> wrote:
>>
>> On 14 March 2014 15:59, Dominic Farr <[email protected]> wrote:
>> > Not sure I fully understand your "component-based configuration system",
>> > so
>> > can you include your configuration at least?
>>
>> The INI configuration is uninteresting - a [urls] section setting up
>> permissions mapped to urls.
>>
>> The component-based config is complex to explain, but could be reduced
>> to the following actual java class (using psuedo code rather than real
>> code):
>>
>> public void initSystem() {
>> // bits I am happy with
>> MyUserDAO dao = ...
>> MyUserRealm realm = new MyUserRealm(dao);
>> SecurityManager sm = new DefaultWebSecurityManager(realm);
>> SecurityUtils.setSecurityManager(sm);
>> // bit that goes wrong
>> Jetty jetty = new EmbeddedJetty();
>> }
>>
>> It goes wrong because embedded jetty reads web.xml and web.xml
>> includes EnvironmentLoaderListener, and that starts its own
>> SecurityManager. I want it to re-use the static one from
>> SecurityUtils.
>>
>>
>> > On PasswordMatcher question, I'm assuming you mean
>> >
>> > https://shiro.apache.org/static/1.2.2/apidocs/org/apache/shiro/authc/credential/PasswordMatcher.html
>> > Shiro uses setter inject over constructor. I think because that is how
>> > ini
>> > works. On this class there are get/set PasswordService.
>>
>> Yes I mean that PasswordMatcher. Not everyone uses the INI format for
>> everything. I'm creating an instanceof PasswordMatcher
>> programmatically, and it is a (minor) pain because it needs three
>> lines instead of one (in order to call the setter). I would consider
>> it good practice for Shiro to provide for setting common elements via
>> the constructor as well as via setters, particularly when the
>> PasswordService is the only setter and it is mandatory!
>>
>> Stephen
>>
>>
>> > On 14 March 2014 15:45, Stephen Colebourne <[email protected]> wrote:
>> >>
>> >> Hi Shiro team,
>> >> I am currently integrating Shiro into our application.
>> >>
>> >> We have our own component-based configuration system which needs to
>> >> operate as follows:
>> >> - start user database component
>> >> - start Shiro PasswordService component
>> >> - start Shiro SeurityManager component
>> >> - start embedded Jetty web server
>> >>
>> >> I can quite happily perform the first three steps, but when I start
>> >> the web server it currently reads a Shiro INI file in
>> >> IniWebEnvironment and sets up a second SecurityManager. Instead, I
>> >> want the existing static SecurityManager to be used. (I want to
>> >> continue using the INI file to setup the filters from the [main] and
>> >> [urls] section).
>> >>
>> >> Have I missed something, or do I just have to hack around with the
>> >> WebEnvironment to write a subclass that re-uses the static
>> >> SecurityManager?
>> >>
>> >> In the embedded Jetty scenario, I think most users would want to
>> >> re-use a static SecurityManager that has been separately created.
>> >>
>> >> Also, as a detail, PasswordMatcher could really do with an additional
>> >> constructor that takes the PasswordService.
>> >>
>> >> thanks
>> >> Stephen
>> >
>> >
>
>