Skip to content

Commit 806e34b

Browse files
author
Vladimir Kotal
committed
add RESTful hooks and unchecked exception on LDAP pool failure
fixes #2740
1 parent efb5082 commit 806e34b

File tree

14 files changed

+286
-32
lines changed

14 files changed

+286
-32
lines changed

opengrok-indexer/src/main/java/org/opengrok/indexer/authorization/AuthorizationStack.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ protected boolean processStack(Nameable entity,
242242

243243
LOGGER.log(Level.FINEST, "AuthEntity \"{0}\" [{1}] testing a name \"{2}\" => {3}",
244244
new Object[]{authEntity.getName(), authEntity.getFlag(), entity.getName(),
245-
pluginDecision ? "true" : "false"});
245+
pluginDecision ? "true" : "false"});
246246

247247
if (!pluginDecision && authEntity.isRequired()) {
248248
// required sets a failure but still invokes all other plugins
@@ -257,6 +257,10 @@ protected boolean processStack(Nameable entity,
257257
overallDecision = true;
258258
break;
259259
}
260+
} catch (LdapException ex) {
261+
// Propagate up so that proper HTTP error can be given.
262+
LOGGER.log(Level.FINEST, "got LDAP exception: " + ex.getMessage());
263+
throw ex;
260264
} catch (Throwable ex) {
261265
LOGGER.log(Level.WARNING,
262266
String.format("AuthEntity \"%s\" has failed the testing of \"%s\" with an exception.",
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* CDDL HEADER START
3+
*
4+
* The contents of this file are subject to the terms of the
5+
* Common Development and Distribution License (the "License").
6+
* You may not use this file except in compliance with the License.
7+
*
8+
* See LICENSE.txt included in this distribution for the specific
9+
* language governing permissions and limitations under the License.
10+
*
11+
* When distributing Covered Code, include this CDDL HEADER in each
12+
* file and include the License file at LICENSE.txt.
13+
* If applicable, add the following below this CDDL HEADER, with the
14+
* fields enclosed by brackets "[]" replaced with your own identifying
15+
* information: Portions Copyright [yyyy] [name of copyright owner]
16+
*
17+
* CDDL HEADER END
18+
*/
19+
20+
/*
21+
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
22+
*/
23+
24+
package org.opengrok.indexer.authorization;
25+
26+
/**
27+
* Unchecked exception to be thrown when LDAP server pool is down.
28+
*/
29+
public class LdapException extends RuntimeException {
30+
public static final long serialVersionUID = -1;
31+
32+
public LdapException() {
33+
super();
34+
}
35+
36+
public LdapException(String str) {
37+
super(str);
38+
}
39+
40+
public LdapException(String str, Throwable ex) {
41+
super(str, ex);
42+
}
43+
}

opengrok-indexer/src/main/java/org/opengrok/indexer/framework/PluginClassLoader.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public class PluginClassLoader extends ClassLoader {
5353
"org.opengrok.indexer.configuration.RuntimeEnvironment",
5454
"org.opengrok.indexer.authorization.IAuthorizationPlugin",
5555
"org.opengrok.indexer.authorization.plugins.*",
56+
"org.opengrok.indexer.authorization.LdapError",
5657
"org.opengrok.indexer.util.*",
5758
"org.opengrok.indexer.logger.*"
5859
};

opengrok-web/src/main/webapp/error.jsp

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ information: Portions Copyright [yyyy] [name of copyright owner]
1616
1717
CDDL HEADER END
1818
19-
Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
19+
Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
2020
Portions Copyright 2011 Jens Elkner.
2121
Portions Copyright (c) 2018, Chris Fraire <[email protected]>.
2222
@@ -55,13 +55,6 @@ include file="pageheader.jspf"
5555
5656
%>
5757
</div>
58-
<div id="Masthead">Error</div>
59-
<div id="sbar"><%@
60-
61-
include file="menu.jspf"
62-
63-
%></div>
64-
</div>
6558
<%
6659
{
6760
PageConfig cfg = PageConfig.get(request);

plugins/pom.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,21 @@ Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
5252
<version>4.12</version>
5353
<scope>test</scope>
5454
</dependency>
55+
<dependency>
56+
<groupId>org.glassfish.jersey.core</groupId>
57+
<artifactId>jersey-client</artifactId>
58+
<version>${jersey.version}</version>
59+
</dependency>
60+
<dependency>
61+
<groupId>org.glassfish.jersey.media</groupId>
62+
<artifactId>jersey-media-json-jackson</artifactId>
63+
<version>${jersey.version}</version>
64+
</dependency>
65+
<dependency>
66+
<groupId>org.glassfish.jersey.inject</groupId>
67+
<artifactId>jersey-hk2</artifactId>
68+
<version>${jersey.version}</version>
69+
</dependency>
5570
</dependencies>
5671

5772
<build>

plugins/src/opengrok/auth/plugin/LdapAttrPlugin.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import java.util.Map;
2929
import java.util.Set;
3030
import java.util.TreeSet;
31+
import java.util.logging.Level;
32+
import java.util.logging.Logger;
3133
import java.util.stream.Stream;
3234
import javax.servlet.http.HttpServletRequest;
3335
import opengrok.auth.entity.LdapUser;
@@ -42,6 +44,9 @@
4244
*/
4345
public class LdapAttrPlugin extends AbstractLdapPlugin {
4446

47+
private static final Logger LOGGER = Logger.getLogger(LdapAttrPlugin.class.getName());
48+
49+
4550
protected static final String ATTR_PARAM = "attribute"; // LDAP attribute name to check
4651
protected static final String FILE_PARAM = "file";
4752

@@ -92,7 +97,7 @@ public void fillSession(HttpServletRequest req, User user) {
9297
updateSession(req, sessionAllowed);
9398

9499
if ((ldapUser = (LdapUser) req.getSession().getAttribute(LdapUserPlugin.SESSION_ATTR)) == null) {
95-
// TODO log
100+
LOGGER.log(Level.FINE, "cannot get {0} attribute", LdapUserPlugin.SESSION_ATTR);
96101
return;
97102
}
98103

plugins/src/opengrok/auth/plugin/LdapFilterPlugin.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,11 @@ protected boolean sessionExists(HttpServletRequest req) {
7171

7272
@Override
7373
public void fillSession(HttpServletRequest req, User user) {
74-
Boolean sessionAllowed = false;
7574
LdapUser ldapUser;
7675
Map<String, Set<String>> records;
7776
String[] dn = {"dn"};
7877

79-
updateSession(req, sessionAllowed);
78+
updateSession(req, false);
8079

8180
if ((ldapUser = (LdapUser) req.getSession().getAttribute(LdapUserPlugin.SESSION_ATTR)) == null) {
8281
LOGGER.log(Level.FINER, "failed to get attribute " + LdapUserPlugin.SESSION_ATTR);
@@ -92,9 +91,8 @@ public void fillSession(HttpServletRequest req, User user) {
9291
}
9392

9493
LOGGER.log(Level.FINER, "got {0} records", records.size());
95-
sessionAllowed = true;
9694

97-
updateSession(req, sessionAllowed);
95+
updateSession(req, true);
9896
}
9997

10098
/**

plugins/src/opengrok/auth/plugin/configuration/Configuration.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,14 @@
3636
import java.util.ArrayList;
3737
import java.util.List;
3838
import opengrok.auth.plugin.ldap.LdapServer;
39+
import opengrok.auth.plugin.util.Hooks;
3940

4041
public class Configuration {
4142

4243
private List<LdapServer> servers = new ArrayList<>();
4344
private int interval;
4445
private String searchBase;
46+
private Hooks hooks;
4547

4648
public void setServers(List<LdapServer> servers) {
4749
this.servers = servers;
@@ -51,6 +53,14 @@ public List<LdapServer> getServers() {
5153
return servers;
5254
}
5355

56+
public void setHooks(Hooks hooks) {
57+
this.hooks = hooks;
58+
}
59+
60+
public Hooks getHooks() {
61+
return hooks;
62+
}
63+
5464
public int getInterval() {
5565
return interval;
5666
}

plugins/src/opengrok/auth/plugin/ldap/LdapFacade.java

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,13 @@
4040
import javax.naming.directory.Attributes;
4141
import javax.naming.directory.SearchControls;
4242
import javax.naming.directory.SearchResult;
43+
4344
import opengrok.auth.plugin.configuration.Configuration;
4445
import opengrok.auth.plugin.entity.User;
46+
import opengrok.auth.plugin.util.Hook;
47+
import opengrok.auth.plugin.util.Hooks;
48+
import org.opengrok.indexer.authorization.LdapException;
49+
import opengrok.auth.plugin.util.RestfulClient;
4550

4651
public class LdapFacade extends AbstractLdapProvider {
4752

@@ -77,7 +82,7 @@ public class LdapFacade extends AbstractLdapProvider {
7782
* Also each server uses this same interval since its last failure - per
7883
* server waiting.
7984
*/
80-
private int interval = 10 * 1000;
85+
private int interval = 10 * 1000; // ms
8186

8287
/**
8388
* LDAP search base
@@ -89,6 +94,11 @@ public class LdapFacade extends AbstractLdapProvider {
8994
*/
9095
private List<LdapServer> servers = new ArrayList<>();
9196

97+
/**
98+
* server hooks
99+
*/
100+
Hooks hooks;
101+
92102
private SearchControls controls;
93103
private int actualServer = 0;
94104
private long errorTimestamp = 0;
@@ -171,10 +181,15 @@ public LdapFacade(Configuration cfg) {
171181
setServers(cfg.getServers());
172182
setInterval(cfg.getInterval());
173183
setSearchBase(cfg.getSearchBase());
184+
setHooks(cfg.getHooks());
174185
prepareSearchControls();
175186
prepareServers();
176187
}
177188

189+
private void setHooks(Hooks hooks) {
190+
this.hooks = hooks;
191+
}
192+
178193
/**
179194
* Finds first working server in the pool.
180195
*/
@@ -255,8 +270,6 @@ public Map<String, Set<String>> lookupLdapContent(User user, String filter, Stri
255270
private SearchControls prepareSearchControls() {
256271
controls = new SearchControls();
257272
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
258-
controls.setTimeLimit(LDAP_TIMEOUT);
259-
controls.setCountLimit(LDAP_COUNT_LIMIT);
260273
return controls;
261274
}
262275

@@ -292,22 +305,26 @@ private <T> T lookup(String dn, String filter, String[] attributes, AttributeMap
292305
if (errorTimestamp > 0 && errorTimestamp + interval > System.currentTimeMillis()) {
293306
if (!reported) {
294307
reported = true;
295-
LOGGER.log(Level.SEVERE, "Server pool is still broken");
308+
LOGGER.log(Level.SEVERE, "LDAP server pool is still broken");
296309
}
297-
return null;
310+
throw new LdapException("LDAP server pool is still broken");
298311
}
299312

300313
if (fail > servers.size() - 1) {
301314
// did the whole rotation
302-
LOGGER.log(Level.SEVERE, "Tried all servers in a pool but no server works");
315+
LOGGER.log(Level.SEVERE, "Tried all LDAP servers in a pool but no server works");
303316
errorTimestamp = System.currentTimeMillis();
304317
reported = false;
305-
return null;
318+
Hook hook;
319+
if ((hook = hooks.getFail()) != null) {
320+
RestfulClient.postIt(hook.getURI(), hook.getContent());
321+
}
322+
throw new LdapException("Tried all LDAP servers in a pool but no server works");
306323
}
307324

308325
if (!isConfigured()) {
309326
LOGGER.log(Level.SEVERE, "LDAP is not configured");
310-
return null;
327+
throw new LdapException("LDAP is not configured");
311328
}
312329

313330
NamingEnumeration<SearchResult> namingEnum = null;
@@ -317,11 +334,17 @@ private <T> T lookup(String dn, String filter, String[] attributes, AttributeMap
317334
for (namingEnum = server.search(dn, filter, controls); namingEnum.hasMore();) {
318335
SearchResult sr = namingEnum.next();
319336
reported = false;
337+
if (errorTimestamp > 0) {
338+
errorTimestamp = 0;
339+
Hook hook;
340+
if ((hook = hooks.getRecover()) != null) {
341+
RestfulClient.postIt(hook.getURI(), hook.getContent());
342+
}
343+
}
320344
return processResult(sr, mapper);
321345
}
322346
} catch (NameNotFoundException ex) {
323-
LOGGER.log(Level.SEVERE, "The LDAP name was not found.", ex);
324-
return null;
347+
throw new LdapException("The LDAP name was not found.", ex);
325348
} catch (SizeLimitExceededException ex) {
326349
LOGGER.log(Level.SEVERE, "The maximum size of the LDAP result has exceeded.", ex);
327350
closeActualServer();
@@ -352,7 +375,8 @@ private <T> T lookup(String dn, String filter, String[] attributes, AttributeMap
352375
}
353376
}
354377
}
355-
return null;
378+
379+
throw new LdapException("LDAP naming problem");
356380
}
357381

358382
private void closeActualServer() {

plugins/src/opengrok/auth/plugin/ldap/LdapServer.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ private synchronized LdapContext connect() {
134134
LOGGER.log(Level.INFO, "Server {0} connecting", this.url);
135135

136136
if (errorTimestamp > 0 && errorTimestamp + interval > System.currentTimeMillis()) {
137-
LOGGER.log(Level.INFO, "Server {0} is down", this.url);
137+
LOGGER.log(Level.INFO, "LDAP server {0} is down", this.url);
138138
close();
139139
return null;
140140
}
@@ -156,10 +156,10 @@ private synchronized LdapContext connect() {
156156
ctx = new InitialLdapContext(env, null);
157157
ctx.reconnect(null);
158158
ctx.setRequestControls(null);
159-
LOGGER.log(Level.INFO, "Connected to server {0}", env.get(Context.PROVIDER_URL));
159+
LOGGER.log(Level.INFO, "Connected to LDAP server {0}", env.get(Context.PROVIDER_URL));
160160
errorTimestamp = 0;
161161
} catch (NamingException ex) {
162-
LOGGER.log(Level.INFO, "Server {0} is not responding", env.get(Context.PROVIDER_URL));
162+
LOGGER.log(Level.INFO, "LDAP server {0} is not responding", env.get(Context.PROVIDER_URL));
163163
errorTimestamp = System.currentTimeMillis();
164164
close();
165165
return ctx = null;
@@ -198,14 +198,16 @@ public NamingEnumeration<SearchResult> search(String name, String filter, Search
198198

199199
if (!isWorking()) {
200200
close();
201-
throw new CommunicationException(String.format("Server \"%s\" is down", env.get(Context.PROVIDER_URL)));
201+
throw new CommunicationException(String.format("LDAP server \"%s\" is down",
202+
env.get(Context.PROVIDER_URL)));
202203
}
203204

204205
if (reconnected) {
205-
LOGGER.log(Level.INFO, "Server {0} reconnect", env.get(Context.PROVIDER_URL));
206+
LOGGER.log(Level.INFO, "LDAP server {0} reconnect", env.get(Context.PROVIDER_URL));
206207
close();
207208
if ((ctx = connect()) == null) {
208-
throw new CommunicationException(String.format("Server \"%s\" cannot reconnect", env.get(Context.PROVIDER_URL)));
209+
throw new CommunicationException(String.format("LDAP server \"%s\" cannot reconnect",
210+
env.get(Context.PROVIDER_URL)));
209211
}
210212
}
211213

0 commit comments

Comments
 (0)