001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.shiro.authc; 018 019import org.apache.activemq.shiro.ConnectionReference; 020import org.apache.activemq.shiro.subject.SubjectConnectionReference; 021import org.apache.shiro.subject.PrincipalCollection; 022import org.apache.shiro.subject.SimplePrincipalCollection; 023import org.apache.shiro.subject.Subject; 024 025import java.util.Collection; 026 027/** 028 * @since 5.10.0 029 */ 030public class DefaultAuthenticationPolicy implements AuthenticationPolicy { 031 032 private boolean vmConnectionAuthenticationRequired = false; 033 private String systemAccountUsername = "system"; 034 private String systemAccountRealmName = "iniRealm"; 035 036 private boolean anonymousAccessAllowed = false; 037 private String anonymousAccountUsername = "anonymous"; 038 private String anonymousAccountRealmName = "iniRealm"; 039 040 public boolean isVmConnectionAuthenticationRequired() { 041 return vmConnectionAuthenticationRequired; 042 } 043 044 public void setVmConnectionAuthenticationRequired(boolean vmConnectionAuthenticationRequired) { 045 this.vmConnectionAuthenticationRequired = vmConnectionAuthenticationRequired; 046 } 047 048 public String getSystemAccountUsername() { 049 return systemAccountUsername; 050 } 051 052 public void setSystemAccountUsername(String systemAccountUsername) { 053 this.systemAccountUsername = systemAccountUsername; 054 } 055 056 public String getSystemAccountRealmName() { 057 return systemAccountRealmName; 058 } 059 060 public void setSystemAccountRealmName(String systemAccountRealmName) { 061 this.systemAccountRealmName = systemAccountRealmName; 062 } 063 064 public boolean isAnonymousAccessAllowed() { 065 return anonymousAccessAllowed; 066 } 067 068 public void setAnonymousAccessAllowed(boolean anonymousAccessAllowed) { 069 this.anonymousAccessAllowed = anonymousAccessAllowed; 070 } 071 072 public String getAnonymousAccountUsername() { 073 return anonymousAccountUsername; 074 } 075 076 public void setAnonymousAccountUsername(String anonymousAccountUsername) { 077 this.anonymousAccountUsername = anonymousAccountUsername; 078 } 079 080 public String getAnonymousAccountRealmName() { 081 return anonymousAccountRealmName; 082 } 083 084 public void setAnonymousAccountRealmName(String anonymousAccountRealmName) { 085 this.anonymousAccountRealmName = anonymousAccountRealmName; 086 } 087 088 /** 089 * Returns {@code true} if the client connection has supplied credentials to authenticate itself, {@code false} 090 * otherwise. 091 * 092 * @param conn the client's connection context 093 * @return {@code true} if the client connection has supplied credentials to authenticate itself, {@code false} 094 * otherwise. 095 */ 096 protected boolean credentialsAvailable(ConnectionReference conn) { 097 return conn.getConnectionInfo().getUserName() != null || conn.getConnectionInfo().getPassword() != null; 098 } 099 100 @Override 101 public boolean isAuthenticationRequired(SubjectConnectionReference conn) { 102 Subject subject = conn.getSubject(); 103 104 if (subject.isAuthenticated()) { 105 //already authenticated: 106 return false; 107 } 108 //subject is not authenticated. Authentication is required by default for all accounts other than 109 //the anonymous user (if enabled) or the vm account (if enabled) 110 if (isAnonymousAccessAllowed()) { 111 if (isAnonymousAccount(subject)) { 112 return false; 113 } 114 } 115 116 if (!isVmConnectionAuthenticationRequired()) { 117 if (isSystemAccount(subject)) { 118 return false; 119 } 120 } 121 122 return true; 123 } 124 125 protected boolean isAnonymousAccount(Subject subject) { 126 PrincipalCollection pc = subject.getPrincipals(); 127 return pc != null && matches(pc, anonymousAccountUsername, anonymousAccountRealmName); 128 } 129 130 protected boolean isSystemAccount(Subject subject) { 131 PrincipalCollection pc = subject.getPrincipals(); 132 return pc != null && matches(pc, systemAccountUsername, systemAccountRealmName); 133 } 134 135 protected boolean matches(PrincipalCollection principals, String username, String realmName) { 136 Collection realmPrincipals = principals.fromRealm(realmName); 137 if (realmPrincipals != null && !realmPrincipals.isEmpty()) { 138 if (realmPrincipals.iterator().next().equals(username)) { 139 return true; 140 } 141 } 142 return false; 143 } 144 145 protected boolean isSystemConnection(ConnectionReference conn) { 146 String remoteAddress = conn.getConnectionContext().getConnection().getRemoteAddress(); 147 return remoteAddress.startsWith("vm:"); 148 } 149 150 @Override 151 public void customizeSubject(Subject.Builder subjectBuilder, ConnectionReference conn) { 152 // We only need to specify a custom identity or authentication state if a normal authentication will not occur. 153 // If the client supplied connection credentials, the AuthenticationFilter will perform a normal authentication, 154 // so we should exit immediately: 155 if (credentialsAvailable(conn)) { 156 return; 157 } 158 159 //The connection cannot be authenticated, potentially implying a system or anonymous connection. Check if so: 160 if (isAssumeIdentity(conn)) { 161 PrincipalCollection assumedIdentity = createAssumedIdentity(conn); 162 subjectBuilder.principals(assumedIdentity); 163 } 164 } 165 166 /** 167 * Returns {@code true} if an unauthenticated connection should still assume a specific identity, {@code false} 168 * otherwise. This method will <em>only</em> be called if there are no connection 169 * {@link #credentialsAvailable(ConnectionReference) credentialsAvailable}. 170 * If a client supplies connection credentials, they will always be used to authenticate the client with that 171 * identity. 172 * <p/> 173 * If {@code true} is returned, the assumed identity will be returned by 174 * {@link #createAssumedIdentity(ConnectionReference) createAssumedIdentity}. 175 * <h3>Warning</h3> 176 * This method exists primarily to support the system and anonymous accounts - it is probably unsafe to return 177 * {@code true} in most other scenarios. 178 * 179 * @param conn a reference to the client's connection 180 * @return {@code true} if an unauthenticated connection should still assume a specific identity, {@code false} 181 * otherwise. 182 */ 183 protected boolean isAssumeIdentity(ConnectionReference conn) { 184 return isAnonymousAccessAllowed() || 185 (isSystemConnection(conn) && !isVmConnectionAuthenticationRequired()); 186 } 187 188 /** 189 * Returns a Shiro {@code PrincipalCollection} representing the identity to assume (without true authentication) for 190 * the specified Connection. 191 * <p/> 192 * This method is <em>only</em> called if {@link #isAssumeIdentity(ConnectionReference)} is {@code true}. 193 * 194 * @param conn a reference to the client's connection 195 * @return a Shiro {@code PrincipalCollection} representing the identity to assume (without true authentication) for 196 * the specified Connection. 197 */ 198 protected PrincipalCollection createAssumedIdentity(ConnectionReference conn) { 199 200 //anonymous by default: 201 String username = anonymousAccountUsername; 202 String realmName = anonymousAccountRealmName; 203 204 //vm connections are special and should assume the system account: 205 if (isSystemConnection(conn)) { 206 username = systemAccountUsername; 207 realmName = systemAccountRealmName; 208 } 209 210 return new SimplePrincipalCollection(username, realmName); 211 } 212}