1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.logging.log4j.core.net;
19
20 import java.net.URI;
21 import java.net.URISyntaxException;
22 import java.util.Properties;
23
24 import javax.naming.Context;
25 import javax.naming.InitialContext;
26 import javax.naming.NamingException;
27
28 import org.apache.logging.log4j.core.appender.AbstractManager;
29 import org.apache.logging.log4j.core.appender.ManagerFactory;
30 import org.apache.logging.log4j.core.util.JndiCloser;
31 import org.apache.logging.log4j.util.PropertiesUtil;
32
33
34
35
36
37
38 public class JndiManager extends AbstractManager {
39
40 private static final JndiManagerFactory FACTORY = new JndiManagerFactory();
41 private static final String PREFIX = "log4j2.enableJndi";
42 private static final String JAVA_SCHEME = "java";
43
44 private static final boolean JNDI_CONTEXT_SELECTOR_ENABLED = isJndiEnabled("ContextSelector");
45 private static final boolean JNDI_JDBC_ENABLED = isJndiEnabled("Jdbc");
46 private static final boolean JNDI_JMS_ENABLED = isJndiEnabled("Jms");
47 private static final boolean JNDI_LOOKUP_ENABLED = isJndiEnabled("Lookup");
48
49 private final InitialContext context;
50
51 private static String createManagerName() {
52 return JndiManager.class.getName() + '@' + JndiManager.class.hashCode();
53 }
54
55 private static boolean isJndiEnabled(final String subKey) {
56 return PropertiesUtil.getProperties().getBooleanProperty(PREFIX + subKey, false);
57 }
58
59 public static boolean isJndiEnabled() {
60 return isJndiContextSelectorEnabled() || isJndiJdbcEnabled() || isJndiJmsEnabled() || isJndiLookupEnabled();
61 }
62
63 public static boolean isJndiContextSelectorEnabled() {
64 return JNDI_CONTEXT_SELECTOR_ENABLED;
65 }
66
67 public static boolean isJndiJdbcEnabled() {
68 return JNDI_JDBC_ENABLED;
69 }
70
71 public static boolean isJndiJmsEnabled() {
72 return JNDI_JMS_ENABLED;
73 }
74
75 public static boolean isJndiLookupEnabled() {
76 return JNDI_LOOKUP_ENABLED;
77 }
78
79 private JndiManager(final String name, final InitialContext context) {
80 super(name);
81 this.context = context;
82 }
83
84
85
86
87
88
89 public static JndiManager getDefaultManager() {
90 return getManager(JndiManager.class.getName(), FACTORY, null);
91 }
92
93
94
95
96
97
98 public static JndiManager getDefaultManager(final String name) {
99 return getManager(name, FACTORY, null);
100 }
101
102
103
104
105
106
107
108
109
110 public static JndiManager getJndiManager(final Properties properties) {
111 return getManager(createManagerName(), FACTORY, properties);
112 }
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127 public static JndiManager getJndiManager(final String initialContextFactoryName,
128 final String providerURL,
129 final String urlPkgPrefixes,
130 final String securityPrincipal,
131 final String securityCredentials,
132 final Properties additionalProperties) {
133 final String name = JndiManager.class.getName() + '@' + JndiManager.class.hashCode();
134 if (initialContextFactoryName == null) {
135 return getManager(name, FACTORY, null);
136 }
137 final Properties properties = new Properties();
138 properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, initialContextFactoryName);
139 if (providerURL != null) {
140 properties.setProperty(Context.PROVIDER_URL, providerURL);
141 } else {
142 LOGGER.warn("The JNDI InitialContextFactory class name [{}] was provided, but there was no associated " +
143 "provider URL. This is likely to cause problems.", initialContextFactoryName);
144 }
145 if (urlPkgPrefixes != null) {
146 properties.setProperty(Context.URL_PKG_PREFIXES, urlPkgPrefixes);
147 }
148 if (securityPrincipal != null) {
149 properties.setProperty(Context.SECURITY_PRINCIPAL, securityPrincipal);
150 if (securityCredentials != null) {
151 properties.setProperty(Context.SECURITY_CREDENTIALS, securityCredentials);
152 } else {
153 LOGGER.warn("A security principal [{}] was provided, but with no corresponding security credentials.",
154 securityPrincipal);
155 }
156 }
157 if (additionalProperties != null) {
158 properties.putAll(additionalProperties);
159 }
160 return getManager(name, FACTORY, properties);
161 }
162
163 @Override
164 protected void releaseSub() {
165 JndiCloser.closeSilently(this.context);
166 }
167
168
169
170
171
172
173
174
175
176 @SuppressWarnings("unchecked")
177 public <T> T lookup(final String name) throws NamingException {
178 if (context == null) {
179 return null;
180 }
181 try {
182 URI uri = new URI(name);
183 if (uri.getScheme() == null || uri.getScheme().equals(JAVA_SCHEME)) {
184 return (T) this.context.lookup(name);
185 }
186 LOGGER.warn("Unsupported JNDI URI - {}", name);
187 } catch (URISyntaxException ex) {
188 LOGGER.warn("Invalid JNDI URI - {}", name);
189 }
190 return null;
191 }
192
193 private static class JndiManagerFactory implements ManagerFactory<JndiManager, Properties> {
194
195 @Override
196 public JndiManager createManager(final String name, final Properties data) {
197 if (!isJndiEnabled()) {
198 throw new IllegalStateException(String.format("JNDI must be enabled by setting one of the %s* properties to true", PREFIX));
199 }
200 try {
201 return new JndiManager(name, new InitialContext(data));
202 } catch (final NamingException e) {
203 LOGGER.error("Error creating JNDI InitialContext.", e);
204 return null;
205 }
206 }
207 }
208 }