001/* 002 * Copyright 2012 Atteo. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.atteo.moonshine.shiro; 017 018import java.util.ArrayList; 019import java.util.Collection; 020import java.util.List; 021 022import javax.inject.Inject; 023import javax.servlet.FilterChain; 024import javax.servlet.ServletRequest; 025import javax.servlet.ServletResponse; 026import javax.xml.bind.annotation.XmlElement; 027import javax.xml.bind.annotation.XmlElementRef; 028import javax.xml.bind.annotation.XmlElementWrapper; 029import javax.xml.bind.annotation.XmlRootElement; 030 031import org.apache.shiro.SecurityUtils; 032import org.apache.shiro.authz.annotation.RequiresGuest; 033import org.apache.shiro.authz.annotation.RequiresPermissions; 034import org.apache.shiro.authz.annotation.RequiresUser; 035import org.apache.shiro.guice.ShiroModule; 036import org.apache.shiro.guice.aop.ShiroAopModule; 037import org.apache.shiro.guice.web.GuiceShiroFilter; 038import org.apache.shiro.guice.web.ShiroWebModule; 039import org.apache.shiro.mgt.SecurityManager; 040import org.apache.shiro.realm.Realm; 041import org.apache.shiro.session.mgt.SessionManager; 042import org.apache.shiro.web.filter.mgt.FilterChainResolver; 043import org.apache.shiro.web.mgt.DefaultWebSecurityManager; 044import org.apache.shiro.web.mgt.WebSecurityManager; 045import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; 046import org.atteo.evo.config.XmlDefaultValue; 047import org.atteo.moonshine.services.Service; 048import org.atteo.moonshine.TopLevelService; 049 050import com.google.inject.Key; 051import com.google.inject.Module; 052import com.google.inject.PrivateModule; 053import com.google.inject.binder.AnnotatedBindingBuilder; 054import com.google.inject.multibindings.Multibinder; 055import com.google.inject.name.Names; 056 057/** 058 * ShiroService service. 059 * 060 * <p> 061 * Binds {@link SecurityManager}. 062 * </p> 063 */ 064@XmlRootElement(name = "shiro") 065public class ShiroService extends TopLevelService { 066 067 /** 068 * Enables Shiro AOP functionality. 069 * 070 * <p> 071 * With Shiro AOP you can use annotations for permission checking: 072 * {@link RequiresPermissions}, {@link RequiresUser}, {@link RequiresGuest}, etc. 073 * </p> 074 */ 075 @XmlElement 076 @XmlDefaultValue("true") 077 private Boolean aop; 078 079 @XmlElementWrapper(name = "realms") 080 @XmlElementRef 081 private List<RealmService> realms = new ArrayList<>(); 082 083 /** 084 * URL prefix to filter through ShiroService. 085 */ 086 @XmlElement 087 private String prefix = "/*"; 088 089 @Override 090 public Iterable<? extends Service> getSubServices() { 091 return realms; 092 } 093 094 @Override 095 public Module configure() { 096 return new PrivateModule() { 097 @Override 098 protected void configure() { 099 install(new ShiroModule() { 100 @Override 101 protected void configureShiro() { 102 Multibinder<Realm> setBinder = Multibinder.newSetBinder(binder(), Realm.class); 103 for (RealmService realm : realms) { 104 if (realm.getId() == null) { 105 setBinder.addBinding().to(Realm.class); 106 } else { 107 setBinder.addBinding().to(Key.get(Realm.class, Names.named(realm.getId()))); 108 } 109 110 } 111 112 try { 113 // Guice will initialize manager with list of realms 114 bind(WebSecurityManager.class).toConstructor( 115 DefaultWebSecurityManager.class.getConstructor(Collection.class)) 116 .asEagerSingleton(); 117 } catch (NoSuchMethodException e) { 118 addError(e); 119 } 120 expose(WebSecurityManager.class); 121 } 122 123 @Override 124 protected void bindSessionManager(AnnotatedBindingBuilder<SessionManager> bind) { 125 // make configurable 126 bind.to(DefaultWebSessionManager.class).asEagerSingleton(); 127 } 128 }); 129 FilterChainResolver filterChainResolver = new FilterChainResolver() { 130 @Override 131 public FilterChain getChain(ServletRequest request, ServletResponse response, 132 FilterChain chain) { 133 return null; 134 } 135 }; 136 bind(FilterChainResolver.class).toInstance(filterChainResolver); 137 138 bind(GuiceShiroFilter.class).asEagerSingleton(); 139 140 install(ShiroWebModule.guiceFilterModule(prefix)); 141 if (aop) { 142 install(new ShiroAopModule()); 143 } 144 145 expose(SecurityManager.class); 146 expose(WebSecurityManager.class); 147 } 148 }; 149 } 150 151 @Inject 152 private SecurityManager securityManager; 153 154 @Override 155 public void start() { 156 SecurityUtils.setSecurityManager(securityManager); 157 } 158 159 @Override 160 public void close() { 161 SecurityUtils.setSecurityManager(null); 162 } 163}