blob: 853843fad7cf87f534dfc374b2bae62972a80a96 [file] [log] [blame]
<!DOCTYPE HTML>
<html lang="en">
<head>
<title>Source code</title>
<link rel="stylesheet" type="text/css" href="../../../../../../stylesheet.css" title="Style">
</head>
<body>
<main role="main">
<div class="sourceContainer">
<pre><span class="sourceLineNo">001</span><a id="line.1">/*</a>
<span class="sourceLineNo">002</span><a id="line.2"> * Licensed to the Apache Software Foundation (ASF) under one</a>
<span class="sourceLineNo">003</span><a id="line.3"> * or more contributor license agreements. See the NOTICE file</a>
<span class="sourceLineNo">004</span><a id="line.4"> * distributed with this work for additional information</a>
<span class="sourceLineNo">005</span><a id="line.5"> * regarding copyright ownership. The ASF licenses this file</a>
<span class="sourceLineNo">006</span><a id="line.6"> * to you under the Apache License, Version 2.0 (the</a>
<span class="sourceLineNo">007</span><a id="line.7"> * "License"); you may not use this file except in compliance</a>
<span class="sourceLineNo">008</span><a id="line.8"> * with the License. You may obtain a copy of the License at</a>
<span class="sourceLineNo">009</span><a id="line.9"> *</a>
<span class="sourceLineNo">010</span><a id="line.10"> * http://www.apache.org/licenses/LICENSE-2.0</a>
<span class="sourceLineNo">011</span><a id="line.11"> *</a>
<span class="sourceLineNo">012</span><a id="line.12"> * Unless required by applicable law or agreed to in writing,</a>
<span class="sourceLineNo">013</span><a id="line.13"> * software distributed under the License is distributed on an</a>
<span class="sourceLineNo">014</span><a id="line.14"> * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY</a>
<span class="sourceLineNo">015</span><a id="line.15"> * KIND, either express or implied. See the License for the</a>
<span class="sourceLineNo">016</span><a id="line.16"> * specific language governing permissions and limitations</a>
<span class="sourceLineNo">017</span><a id="line.17"> * under the License.</a>
<span class="sourceLineNo">018</span><a id="line.18"> */</a>
<span class="sourceLineNo">019</span><a id="line.19">package org.apache.shiro.authc.pam;</a>
<span class="sourceLineNo">020</span><a id="line.20"></a>
<span class="sourceLineNo">021</span><a id="line.21">import org.apache.shiro.authc.*;</a>
<span class="sourceLineNo">022</span><a id="line.22">import org.apache.shiro.realm.Realm;</a>
<span class="sourceLineNo">023</span><a id="line.23">import org.apache.shiro.subject.PrincipalCollection;</a>
<span class="sourceLineNo">024</span><a id="line.24">import org.apache.shiro.util.CollectionUtils;</a>
<span class="sourceLineNo">025</span><a id="line.25">import org.slf4j.Logger;</a>
<span class="sourceLineNo">026</span><a id="line.26">import org.slf4j.LoggerFactory;</a>
<span class="sourceLineNo">027</span><a id="line.27"></a>
<span class="sourceLineNo">028</span><a id="line.28">import java.util.Collection;</a>
<span class="sourceLineNo">029</span><a id="line.29"></a>
<span class="sourceLineNo">030</span><a id="line.30">/**</a>
<span class="sourceLineNo">031</span><a id="line.31"> * A {@code ModularRealmAuthenticator} delegates account lookups to a pluggable (modular) collection of</a>
<span class="sourceLineNo">032</span><a id="line.32"> * {@link Realm}s. This enables PAM (Pluggable Authentication Module) behavior in Shiro.</a>
<span class="sourceLineNo">033</span><a id="line.33"> * In addition to authorization duties, a Shiro Realm can also be thought of a PAM 'module'.</a>
<span class="sourceLineNo">034</span><a id="line.34"> * &lt;p/&gt;</a>
<span class="sourceLineNo">035</span><a id="line.35"> * Using this Authenticator allows you to &amp;quot;plug-in&amp;quot; your own</a>
<span class="sourceLineNo">036</span><a id="line.36"> * {@code Realm}s as you see fit. Common realms are those based on accessing</a>
<span class="sourceLineNo">037</span><a id="line.37"> * LDAP, relational databases, file systems, etc.</a>
<span class="sourceLineNo">038</span><a id="line.38"> * &lt;p/&gt;</a>
<span class="sourceLineNo">039</span><a id="line.39"> * If only one realm is configured (this is often the case for most applications), authentication success is naturally</a>
<span class="sourceLineNo">040</span><a id="line.40"> * only dependent upon invoking this one Realm's</a>
<span class="sourceLineNo">041</span><a id="line.41"> * {@link Realm#getAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)} method.</a>
<span class="sourceLineNo">042</span><a id="line.42"> * &lt;p/&gt;</a>
<span class="sourceLineNo">043</span><a id="line.43"> * But if two or more realms are configured, PAM behavior is implemented by iterating over the collection of realms</a>
<span class="sourceLineNo">044</span><a id="line.44"> * and interacting with each over the course of the authentication attempt. As this is more complicated, this</a>
<span class="sourceLineNo">045</span><a id="line.45"> * authenticator allows customized behavior for interpreting what happens when interacting with multiple realms - for</a>
<span class="sourceLineNo">046</span><a id="line.46"> * example, you might require all realms to be successful during the attempt, or perhaps only at least one must be</a>
<span class="sourceLineNo">047</span><a id="line.47"> * successful, or some other interpretation. This customized behavior can be performed via the use of a</a>
<span class="sourceLineNo">048</span><a id="line.48"> * {@link #setAuthenticationStrategy(AuthenticationStrategy) AuthenticationStrategy}, which</a>
<span class="sourceLineNo">049</span><a id="line.49"> * you can inject as a property of this class.</a>
<span class="sourceLineNo">050</span><a id="line.50"> * &lt;p/&gt;</a>
<span class="sourceLineNo">051</span><a id="line.51"> * The strategy object provides callback methods that allow you to</a>
<span class="sourceLineNo">052</span><a id="line.52"> * determine what constitutes a success or failure in a multi-realm (PAM) scenario. And because this only makes sense</a>
<span class="sourceLineNo">053</span><a id="line.53"> * in a multi-realm scenario, the strategy object is only utilized when more than one Realm is configured.</a>
<span class="sourceLineNo">054</span><a id="line.54"> * &lt;p/&gt;</a>
<span class="sourceLineNo">055</span><a id="line.55"> * As most multi-realm applications require at least one Realm authenticates successfully, the default</a>
<span class="sourceLineNo">056</span><a id="line.56"> * implementation is the {@link AtLeastOneSuccessfulStrategy}.</a>
<span class="sourceLineNo">057</span><a id="line.57"> *</a>
<span class="sourceLineNo">058</span><a id="line.58"> * @see #setRealms</a>
<span class="sourceLineNo">059</span><a id="line.59"> * @see AtLeastOneSuccessfulStrategy</a>
<span class="sourceLineNo">060</span><a id="line.60"> * @see AllSuccessfulStrategy</a>
<span class="sourceLineNo">061</span><a id="line.61"> * @see FirstSuccessfulStrategy</a>
<span class="sourceLineNo">062</span><a id="line.62"> * @since 0.1</a>
<span class="sourceLineNo">063</span><a id="line.63"> */</a>
<span class="sourceLineNo">064</span><a id="line.64">public class ModularRealmAuthenticator extends AbstractAuthenticator {</a>
<span class="sourceLineNo">065</span><a id="line.65"></a>
<span class="sourceLineNo">066</span><a id="line.66"> /*--------------------------------------------</a>
<span class="sourceLineNo">067</span><a id="line.67"> | C O N S T A N T S |</a>
<span class="sourceLineNo">068</span><a id="line.68"> ============================================*/</a>
<span class="sourceLineNo">069</span><a id="line.69"> private static final Logger log = LoggerFactory.getLogger(ModularRealmAuthenticator.class);</a>
<span class="sourceLineNo">070</span><a id="line.70"></a>
<span class="sourceLineNo">071</span><a id="line.71"> /*--------------------------------------------</a>
<span class="sourceLineNo">072</span><a id="line.72"> | I N S T A N C E V A R I A B L E S |</a>
<span class="sourceLineNo">073</span><a id="line.73"> ============================================*/</a>
<span class="sourceLineNo">074</span><a id="line.74"> /**</a>
<span class="sourceLineNo">075</span><a id="line.75"> * List of realms that will be iterated through when a user authenticates.</a>
<span class="sourceLineNo">076</span><a id="line.76"> */</a>
<span class="sourceLineNo">077</span><a id="line.77"> private Collection&lt;Realm&gt; realms;</a>
<span class="sourceLineNo">078</span><a id="line.78"></a>
<span class="sourceLineNo">079</span><a id="line.79"> /**</a>
<span class="sourceLineNo">080</span><a id="line.80"> * The authentication strategy to use during authentication attempts, defaults to a</a>
<span class="sourceLineNo">081</span><a id="line.81"> * {@link org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy} instance.</a>
<span class="sourceLineNo">082</span><a id="line.82"> */</a>
<span class="sourceLineNo">083</span><a id="line.83"> private AuthenticationStrategy authenticationStrategy;</a>
<span class="sourceLineNo">084</span><a id="line.84"></a>
<span class="sourceLineNo">085</span><a id="line.85"> /*--------------------------------------------</a>
<span class="sourceLineNo">086</span><a id="line.86"> | C O N S T R U C T O R S |</a>
<span class="sourceLineNo">087</span><a id="line.87"> ============================================*/</a>
<span class="sourceLineNo">088</span><a id="line.88"></a>
<span class="sourceLineNo">089</span><a id="line.89"> /**</a>
<span class="sourceLineNo">090</span><a id="line.90"> * Default no-argument constructor which</a>
<span class="sourceLineNo">091</span><a id="line.91"> * {@link #setAuthenticationStrategy(AuthenticationStrategy) enables} an</a>
<span class="sourceLineNo">092</span><a id="line.92"> * {@link org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy} by default.</a>
<span class="sourceLineNo">093</span><a id="line.93"> */</a>
<span class="sourceLineNo">094</span><a id="line.94"> public ModularRealmAuthenticator() {</a>
<span class="sourceLineNo">095</span><a id="line.95"> this.authenticationStrategy = new AtLeastOneSuccessfulStrategy();</a>
<span class="sourceLineNo">096</span><a id="line.96"> }</a>
<span class="sourceLineNo">097</span><a id="line.97"></a>
<span class="sourceLineNo">098</span><a id="line.98"> /*--------------------------------------------</a>
<span class="sourceLineNo">099</span><a id="line.99"> | A C C E S S O R S / M O D I F I E R S |</a>
<span class="sourceLineNo">100</span><a id="line.100"> ============================================*/</a>
<span class="sourceLineNo">101</span><a id="line.101"></a>
<span class="sourceLineNo">102</span><a id="line.102"> /**</a>
<span class="sourceLineNo">103</span><a id="line.103"> * Sets all realms used by this Authenticator, providing PAM (Pluggable Authentication Module) configuration.</a>
<span class="sourceLineNo">104</span><a id="line.104"> *</a>
<span class="sourceLineNo">105</span><a id="line.105"> * @param realms the realms to consult during authentication attempts.</a>
<span class="sourceLineNo">106</span><a id="line.106"> */</a>
<span class="sourceLineNo">107</span><a id="line.107"> public void setRealms(Collection&lt;Realm&gt; realms) {</a>
<span class="sourceLineNo">108</span><a id="line.108"> this.realms = realms;</a>
<span class="sourceLineNo">109</span><a id="line.109"> }</a>
<span class="sourceLineNo">110</span><a id="line.110"></a>
<span class="sourceLineNo">111</span><a id="line.111"> /**</a>
<span class="sourceLineNo">112</span><a id="line.112"> * Returns the realm(s) used by this {@code Authenticator} during an authentication attempt.</a>
<span class="sourceLineNo">113</span><a id="line.113"> *</a>
<span class="sourceLineNo">114</span><a id="line.114"> * @return the realm(s) used by this {@code Authenticator} during an authentication attempt.</a>
<span class="sourceLineNo">115</span><a id="line.115"> */</a>
<span class="sourceLineNo">116</span><a id="line.116"> protected Collection&lt;Realm&gt; getRealms() {</a>
<span class="sourceLineNo">117</span><a id="line.117"> return this.realms;</a>
<span class="sourceLineNo">118</span><a id="line.118"> }</a>
<span class="sourceLineNo">119</span><a id="line.119"></a>
<span class="sourceLineNo">120</span><a id="line.120"> /**</a>
<span class="sourceLineNo">121</span><a id="line.121"> * Returns the {@code AuthenticationStrategy} utilized by this modular authenticator during a multi-realm</a>
<span class="sourceLineNo">122</span><a id="line.122"> * log-in attempt. This object is only used when two or more Realms are configured.</a>
<span class="sourceLineNo">123</span><a id="line.123"> * &lt;p/&gt;</a>
<span class="sourceLineNo">124</span><a id="line.124"> * Unless overridden by</a>
<span class="sourceLineNo">125</span><a id="line.125"> * the {@link #setAuthenticationStrategy(AuthenticationStrategy)} method, the default implementation</a>
<span class="sourceLineNo">126</span><a id="line.126"> * is the {@link org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy}.</a>
<span class="sourceLineNo">127</span><a id="line.127"> *</a>
<span class="sourceLineNo">128</span><a id="line.128"> * @return the {@code AuthenticationStrategy} utilized by this modular authenticator during a log-in attempt.</a>
<span class="sourceLineNo">129</span><a id="line.129"> * @since 0.2</a>
<span class="sourceLineNo">130</span><a id="line.130"> */</a>
<span class="sourceLineNo">131</span><a id="line.131"> public AuthenticationStrategy getAuthenticationStrategy() {</a>
<span class="sourceLineNo">132</span><a id="line.132"> return authenticationStrategy;</a>
<span class="sourceLineNo">133</span><a id="line.133"> }</a>
<span class="sourceLineNo">134</span><a id="line.134"></a>
<span class="sourceLineNo">135</span><a id="line.135"> /**</a>
<span class="sourceLineNo">136</span><a id="line.136"> * Allows overriding the default {@code AuthenticationStrategy} utilized during multi-realm log-in attempts.</a>
<span class="sourceLineNo">137</span><a id="line.137"> * This object is only used when two or more Realms are configured.</a>
<span class="sourceLineNo">138</span><a id="line.138"> *</a>
<span class="sourceLineNo">139</span><a id="line.139"> * @param authenticationStrategy the strategy implementation to use during log-in attempts.</a>
<span class="sourceLineNo">140</span><a id="line.140"> * @since 0.2</a>
<span class="sourceLineNo">141</span><a id="line.141"> */</a>
<span class="sourceLineNo">142</span><a id="line.142"> public void setAuthenticationStrategy(AuthenticationStrategy authenticationStrategy) {</a>
<span class="sourceLineNo">143</span><a id="line.143"> this.authenticationStrategy = authenticationStrategy;</a>
<span class="sourceLineNo">144</span><a id="line.144"> }</a>
<span class="sourceLineNo">145</span><a id="line.145"></a>
<span class="sourceLineNo">146</span><a id="line.146"> /*--------------------------------------------</a>
<span class="sourceLineNo">147</span><a id="line.147"> | M E T H O D S |</a>
<span class="sourceLineNo">148</span><a id="line.148"></a>
<span class="sourceLineNo">149</span><a id="line.149"> /**</a>
<span class="sourceLineNo">150</span><a id="line.150"> * Used by the internal {@link #doAuthenticate} implementation to ensure that the {@code realms} property</a>
<span class="sourceLineNo">151</span><a id="line.151"> * has been set. The default implementation ensures the property is not null and not empty.</a>
<span class="sourceLineNo">152</span><a id="line.152"> *</a>
<span class="sourceLineNo">153</span><a id="line.153"> * @throws IllegalStateException if the {@code realms} property is configured incorrectly.</a>
<span class="sourceLineNo">154</span><a id="line.154"> */</a>
<span class="sourceLineNo">155</span><a id="line.155"></a>
<span class="sourceLineNo">156</span><a id="line.156"> protected void assertRealmsConfigured() throws IllegalStateException {</a>
<span class="sourceLineNo">157</span><a id="line.157"> Collection&lt;Realm&gt; realms = getRealms();</a>
<span class="sourceLineNo">158</span><a id="line.158"> if (CollectionUtils.isEmpty(realms)) {</a>
<span class="sourceLineNo">159</span><a id="line.159"> String msg = "Configuration error: No realms have been configured! One or more realms must be " +</a>
<span class="sourceLineNo">160</span><a id="line.160"> "present to execute an authentication attempt.";</a>
<span class="sourceLineNo">161</span><a id="line.161"> throw new IllegalStateException(msg);</a>
<span class="sourceLineNo">162</span><a id="line.162"> }</a>
<span class="sourceLineNo">163</span><a id="line.163"> }</a>
<span class="sourceLineNo">164</span><a id="line.164"></a>
<span class="sourceLineNo">165</span><a id="line.165"> /**</a>
<span class="sourceLineNo">166</span><a id="line.166"> * Performs the authentication attempt by interacting with the single configured realm, which is significantly</a>
<span class="sourceLineNo">167</span><a id="line.167"> * simpler than performing multi-realm logic.</a>
<span class="sourceLineNo">168</span><a id="line.168"> *</a>
<span class="sourceLineNo">169</span><a id="line.169"> * @param realm the realm to consult for AuthenticationInfo.</a>
<span class="sourceLineNo">170</span><a id="line.170"> * @param token the submitted AuthenticationToken representing the subject's (user's) log-in principals and credentials.</a>
<span class="sourceLineNo">171</span><a id="line.171"> * @return the AuthenticationInfo associated with the user account corresponding to the specified {@code token}</a>
<span class="sourceLineNo">172</span><a id="line.172"> */</a>
<span class="sourceLineNo">173</span><a id="line.173"> protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) {</a>
<span class="sourceLineNo">174</span><a id="line.174"> if (!realm.supports(token)) {</a>
<span class="sourceLineNo">175</span><a id="line.175"> String msg = "Realm [" + realm + "] does not support authentication token [" +</a>
<span class="sourceLineNo">176</span><a id="line.176"> token + "]. Please ensure that the appropriate Realm implementation is " +</a>
<span class="sourceLineNo">177</span><a id="line.177"> "configured correctly or that the realm accepts AuthenticationTokens of this type.";</a>
<span class="sourceLineNo">178</span><a id="line.178"> throw new UnsupportedTokenException(msg);</a>
<span class="sourceLineNo">179</span><a id="line.179"> }</a>
<span class="sourceLineNo">180</span><a id="line.180"> AuthenticationInfo info = realm.getAuthenticationInfo(token);</a>
<span class="sourceLineNo">181</span><a id="line.181"> if (info == null) {</a>
<span class="sourceLineNo">182</span><a id="line.182"> String msg = "Realm [" + realm + "] was unable to find account data for the " +</a>
<span class="sourceLineNo">183</span><a id="line.183"> "submitted AuthenticationToken [" + token + "].";</a>
<span class="sourceLineNo">184</span><a id="line.184"> throw new UnknownAccountException(msg);</a>
<span class="sourceLineNo">185</span><a id="line.185"> }</a>
<span class="sourceLineNo">186</span><a id="line.186"> return info;</a>
<span class="sourceLineNo">187</span><a id="line.187"> }</a>
<span class="sourceLineNo">188</span><a id="line.188"></a>
<span class="sourceLineNo">189</span><a id="line.189"> /**</a>
<span class="sourceLineNo">190</span><a id="line.190"> * Performs the multi-realm authentication attempt by calling back to a {@link AuthenticationStrategy} object</a>
<span class="sourceLineNo">191</span><a id="line.191"> * as each realm is consulted for {@code AuthenticationInfo} for the specified {@code token}.</a>
<span class="sourceLineNo">192</span><a id="line.192"> *</a>
<span class="sourceLineNo">193</span><a id="line.193"> * @param realms the multiple realms configured on this Authenticator instance.</a>
<span class="sourceLineNo">194</span><a id="line.194"> * @param token the submitted AuthenticationToken representing the subject's (user's) log-in principals and credentials.</a>
<span class="sourceLineNo">195</span><a id="line.195"> * @return an aggregated AuthenticationInfo instance representing account data across all the successfully</a>
<span class="sourceLineNo">196</span><a id="line.196"> * consulted realms.</a>
<span class="sourceLineNo">197</span><a id="line.197"> */</a>
<span class="sourceLineNo">198</span><a id="line.198"> protected AuthenticationInfo doMultiRealmAuthentication(Collection&lt;Realm&gt; realms, AuthenticationToken token) {</a>
<span class="sourceLineNo">199</span><a id="line.199"></a>
<span class="sourceLineNo">200</span><a id="line.200"> AuthenticationStrategy strategy = getAuthenticationStrategy();</a>
<span class="sourceLineNo">201</span><a id="line.201"></a>
<span class="sourceLineNo">202</span><a id="line.202"> AuthenticationInfo aggregate = strategy.beforeAllAttempts(realms, token);</a>
<span class="sourceLineNo">203</span><a id="line.203"></a>
<span class="sourceLineNo">204</span><a id="line.204"> if (log.isTraceEnabled()) {</a>
<span class="sourceLineNo">205</span><a id="line.205"> log.trace("Iterating through {} realms for PAM authentication", realms.size());</a>
<span class="sourceLineNo">206</span><a id="line.206"> }</a>
<span class="sourceLineNo">207</span><a id="line.207"></a>
<span class="sourceLineNo">208</span><a id="line.208"> for (Realm realm : realms) {</a>
<span class="sourceLineNo">209</span><a id="line.209"></a>
<span class="sourceLineNo">210</span><a id="line.210"> try {</a>
<span class="sourceLineNo">211</span><a id="line.211"> aggregate = strategy.beforeAttempt(realm, token, aggregate);</a>
<span class="sourceLineNo">212</span><a id="line.212"> } catch (ShortCircuitIterationException shortCircuitSignal) {</a>
<span class="sourceLineNo">213</span><a id="line.213"> // Break from continuing with subsequnet realms on receiving </a>
<span class="sourceLineNo">214</span><a id="line.214"> // short circuit signal from strategy</a>
<span class="sourceLineNo">215</span><a id="line.215"> break;</a>
<span class="sourceLineNo">216</span><a id="line.216"> }</a>
<span class="sourceLineNo">217</span><a id="line.217"></a>
<span class="sourceLineNo">218</span><a id="line.218"> if (realm.supports(token)) {</a>
<span class="sourceLineNo">219</span><a id="line.219"></a>
<span class="sourceLineNo">220</span><a id="line.220"> log.trace("Attempting to authenticate token [{}] using realm [{}]", token, realm);</a>
<span class="sourceLineNo">221</span><a id="line.221"></a>
<span class="sourceLineNo">222</span><a id="line.222"> AuthenticationInfo info = null;</a>
<span class="sourceLineNo">223</span><a id="line.223"> Throwable t = null;</a>
<span class="sourceLineNo">224</span><a id="line.224"> try {</a>
<span class="sourceLineNo">225</span><a id="line.225"> info = realm.getAuthenticationInfo(token);</a>
<span class="sourceLineNo">226</span><a id="line.226"> } catch (Throwable throwable) {</a>
<span class="sourceLineNo">227</span><a id="line.227"> t = throwable;</a>
<span class="sourceLineNo">228</span><a id="line.228"> if (log.isDebugEnabled()) {</a>
<span class="sourceLineNo">229</span><a id="line.229"> String msg = "Realm [" + realm + "] threw an exception during a multi-realm authentication attempt:";</a>
<span class="sourceLineNo">230</span><a id="line.230"> log.debug(msg, t);</a>
<span class="sourceLineNo">231</span><a id="line.231"> }</a>
<span class="sourceLineNo">232</span><a id="line.232"> }</a>
<span class="sourceLineNo">233</span><a id="line.233"></a>
<span class="sourceLineNo">234</span><a id="line.234"> aggregate = strategy.afterAttempt(realm, token, info, aggregate, t);</a>
<span class="sourceLineNo">235</span><a id="line.235"></a>
<span class="sourceLineNo">236</span><a id="line.236"> } else {</a>
<span class="sourceLineNo">237</span><a id="line.237"> log.debug("Realm [{}] does not support token {}. Skipping realm.", realm, token);</a>
<span class="sourceLineNo">238</span><a id="line.238"> }</a>
<span class="sourceLineNo">239</span><a id="line.239"> }</a>
<span class="sourceLineNo">240</span><a id="line.240"></a>
<span class="sourceLineNo">241</span><a id="line.241"> aggregate = strategy.afterAllAttempts(token, aggregate);</a>
<span class="sourceLineNo">242</span><a id="line.242"></a>
<span class="sourceLineNo">243</span><a id="line.243"> return aggregate;</a>
<span class="sourceLineNo">244</span><a id="line.244"> }</a>
<span class="sourceLineNo">245</span><a id="line.245"></a>
<span class="sourceLineNo">246</span><a id="line.246"></a>
<span class="sourceLineNo">247</span><a id="line.247"> /**</a>
<span class="sourceLineNo">248</span><a id="line.248"> * Attempts to authenticate the given token by iterating over the internal collection of</a>
<span class="sourceLineNo">249</span><a id="line.249"> * {@link Realm}s. For each realm, first the {@link Realm#supports(org.apache.shiro.authc.AuthenticationToken)}</a>
<span class="sourceLineNo">250</span><a id="line.250"> * method will be called to determine if the realm supports the {@code authenticationToken} method argument.</a>
<span class="sourceLineNo">251</span><a id="line.251"> * &lt;p/&gt;</a>
<span class="sourceLineNo">252</span><a id="line.252"> * If a realm does support</a>
<span class="sourceLineNo">253</span><a id="line.253"> * the token, its {@link Realm#getAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)}</a>
<span class="sourceLineNo">254</span><a id="line.254"> * method will be called. If the realm returns a non-null account, the token will be</a>
<span class="sourceLineNo">255</span><a id="line.255"> * considered authenticated for that realm and the account data recorded. If the realm returns {@code null},</a>
<span class="sourceLineNo">256</span><a id="line.256"> * the next realm will be consulted. If no realms support the token or all supporting realms return null,</a>
<span class="sourceLineNo">257</span><a id="line.257"> * an {@link AuthenticationException} will be thrown to indicate that the user could not be authenticated.</a>
<span class="sourceLineNo">258</span><a id="line.258"> * &lt;p/&gt;</a>
<span class="sourceLineNo">259</span><a id="line.259"> * After all realms have been consulted, the information from each realm is aggregated into a single</a>
<span class="sourceLineNo">260</span><a id="line.260"> * {@link AuthenticationInfo} object and returned.</a>
<span class="sourceLineNo">261</span><a id="line.261"> *</a>
<span class="sourceLineNo">262</span><a id="line.262"> * @param authenticationToken the token containing the authentication principal and credentials for the</a>
<span class="sourceLineNo">263</span><a id="line.263"> * user being authenticated.</a>
<span class="sourceLineNo">264</span><a id="line.264"> * @return account information attributed to the authenticated user.</a>
<span class="sourceLineNo">265</span><a id="line.265"> * @throws IllegalStateException if no realms have been configured at the time this method is invoked</a>
<span class="sourceLineNo">266</span><a id="line.266"> * @throws AuthenticationException if the user could not be authenticated or the user is denied authentication</a>
<span class="sourceLineNo">267</span><a id="line.267"> * for the given principal and credentials.</a>
<span class="sourceLineNo">268</span><a id="line.268"> */</a>
<span class="sourceLineNo">269</span><a id="line.269"> protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {</a>
<span class="sourceLineNo">270</span><a id="line.270"> assertRealmsConfigured();</a>
<span class="sourceLineNo">271</span><a id="line.271"> Collection&lt;Realm&gt; realms = getRealms();</a>
<span class="sourceLineNo">272</span><a id="line.272"> if (realms.size() == 1) {</a>
<span class="sourceLineNo">273</span><a id="line.273"> return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken);</a>
<span class="sourceLineNo">274</span><a id="line.274"> } else {</a>
<span class="sourceLineNo">275</span><a id="line.275"> return doMultiRealmAuthentication(realms, authenticationToken);</a>
<span class="sourceLineNo">276</span><a id="line.276"> }</a>
<span class="sourceLineNo">277</span><a id="line.277"> }</a>
<span class="sourceLineNo">278</span><a id="line.278"></a>
<span class="sourceLineNo">279</span><a id="line.279"> /**</a>
<span class="sourceLineNo">280</span><a id="line.280"> * First calls &lt;code&gt;super.onLogout(principals)&lt;/code&gt; to ensure a logout notification is issued, and for each</a>
<span class="sourceLineNo">281</span><a id="line.281"> * wrapped {@code Realm} that implements the {@link LogoutAware LogoutAware} interface, calls</a>
<span class="sourceLineNo">282</span><a id="line.282"> * &lt;code&gt;((LogoutAware)realm).onLogout(principals)&lt;/code&gt; to allow each realm the opportunity to perform</a>
<span class="sourceLineNo">283</span><a id="line.283"> * logout/cleanup operations during an user-logout.</a>
<span class="sourceLineNo">284</span><a id="line.284"> * &lt;p/&gt;</a>
<span class="sourceLineNo">285</span><a id="line.285"> * Shiro's Realm implementations all implement the {@code LogoutAware} interface by default and can be</a>
<span class="sourceLineNo">286</span><a id="line.286"> * overridden for realm-specific logout logic.</a>
<span class="sourceLineNo">287</span><a id="line.287"> *</a>
<span class="sourceLineNo">288</span><a id="line.288"> * @param principals the application-specific Subject/user identifier.</a>
<span class="sourceLineNo">289</span><a id="line.289"> */</a>
<span class="sourceLineNo">290</span><a id="line.290"> public void onLogout(PrincipalCollection principals) {</a>
<span class="sourceLineNo">291</span><a id="line.291"> super.onLogout(principals);</a>
<span class="sourceLineNo">292</span><a id="line.292"> Collection&lt;Realm&gt; realms = getRealms();</a>
<span class="sourceLineNo">293</span><a id="line.293"> if (!CollectionUtils.isEmpty(realms)) {</a>
<span class="sourceLineNo">294</span><a id="line.294"> for (Realm realm : realms) {</a>
<span class="sourceLineNo">295</span><a id="line.295"> if (realm instanceof LogoutAware) {</a>
<span class="sourceLineNo">296</span><a id="line.296"> ((LogoutAware) realm).onLogout(principals);</a>
<span class="sourceLineNo">297</span><a id="line.297"> }</a>
<span class="sourceLineNo">298</span><a id="line.298"> }</a>
<span class="sourceLineNo">299</span><a id="line.299"> }</a>
<span class="sourceLineNo">300</span><a id="line.300"> }</a>
<span class="sourceLineNo">301</span><a id="line.301">}</a>
</pre>
</div>
</main>
</body>
</html>