Skip to content

Commit 3da0bf7

Browse files
Merge pull request #33677 from karel-harjono/enhance-user-registry-api
1. added `getAttributesForUser()` and `getUsersByAttribute()` UserRegistry API as default methods. 2. updated internal SearchBridge to get the user attribute information. 3. added FAT tests for `getAttributesForUser()` and `getUsersByAttribute()`. 4. general code review changes.
2 parents 4294f72 + bd28075 commit 3da0bf7

File tree

18 files changed

+837
-78
lines changed

18 files changed

+837
-78
lines changed

dev/com.ibm.websphere.appserver.api.basics/bnd.bnd

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#*******************************************************************************
2-
# Copyright (c) 2017, 2022 IBM Corporation and others.
2+
# Copyright (c) 2017, 2026 IBM Corporation and others.
33
# All rights reserved. This program and the accompanying materials
44
# are made available under the terms of the Eclipse Public License 2.0
55
# which accompanies this distribution, and is available at
@@ -11,7 +11,7 @@
1111
# IBM Corporation - initial API and implementation
1212
#*******************************************************************************
1313
-include= ~../cnf/resources/bnd/bundle.props
14-
bVersion: 1.4
14+
bVersion: 1.5
1515

1616
Bundle-Name: WebSphere Application Manager API
1717
Bundle-Description: WebSphere Application Manager API, version ${bVersion}

dev/com.ibm.websphere.appserver.features/visibility/protected/com.ibm.websphere.appserver.appmanager-1.0.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ IBM-Process-Types: server, \
2222
com.ibm.ws.app.manager.ready; start-phase:=APPLICATION
2323
-jars=com.ibm.websphere.appserver.api.basics; location:="dev/api/ibm/,lib/",\
2424
com.ibm.websphere.appserver.spi.application; location:=dev/spi/ibm/
25-
-files=dev/api/ibm/javadoc/com.ibm.websphere.appserver.api.basics_1.4-javadoc.zip, \
25+
-files=dev/api/ibm/javadoc/com.ibm.websphere.appserver.api.basics_1.5-javadoc.zip, \
2626
dev/spi/ibm/javadoc/com.ibm.websphere.appserver.spi.application_1.1-javadoc.zip
2727
kind=ga
2828
edition=core

dev/com.ibm.websphere.security/src/com/ibm/websphere/security/UserRegistry.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import java.rmi.RemoteException;
1616
import java.security.cert.X509Certificate;
1717
import java.util.List;
18+
import java.util.Map;
19+
import java.util.Set;
1820

1921
/**
2022
* Registries. This should extend java.rmi.Remote as the registry can be in
@@ -393,4 +395,43 @@ public interface UserRegistry extends java.rmi.Remote {
393395
*
394396
**/
395397
public com.ibm.websphere.security.cred.WSCredential createCredential(String userSecurityName) throws NotImplementedException, EntryNotFoundException, CustomRegistryException, RemoteException;
398+
399+
/**
400+
* Returns the attributes for <i>userSecurityName</i>.
401+
*
402+
* @param userSecurityName the name of the user.
403+
* @param attributeNames
404+
* @return a Map of attributes for the user.
405+
* <code>null</code> is not returned.
406+
* @exception EntryNotFoundException if userSecurityName does not exist.
407+
* @exception CustomRegistryException if there is any registry specific problem
408+
**/
409+
@Deprecated
410+
default Map<String, Object> getAttributesForUser(String userSecurityName, Set<String> attributeNames) throws EntryNotFoundException, CustomRegistryException, NotImplementedException {
411+
throw new NotImplementedException("Reading user attributes is not supported.");
412+
}
413+
414+
/**
415+
* Gets a list of users that match an <i>attributeName</i> with specified
416+
* <i>value</i> in the UserRegistry.
417+
* The maximum number of users returned is defined by the <i>limit</i>
418+
* argument. This is very useful in situations where there are thousands of
419+
* users in the UserRegistry and getting all of them at once is not
420+
* practical.
421+
*
422+
* @param attributeName the attributeName to match.
423+
* @param value the value of the attributeName to match.
424+
* @param limit the maximum number of users that should be returned.
425+
* A value of 0 implies get all the users.
426+
* Specifying a negative value returns an empty Result.
427+
* @return a <i>Result</i> object that contains the list of users
428+
* requested and a flag to indicate if more users exist.
429+
* <code>null</code> is not returned.
430+
* @exception CustomRegistryException if there is any UserRegistry specific problem
431+
**/
432+
@Deprecated
433+
default Result getUsersByAttribute(String attributeName, String value, int limit) throws CustomRegistryException, NotImplementedException {
434+
throw new NotImplementedException("Finding users from their attributes is not supported.");
435+
}
436+
396437
}

dev/com.ibm.websphere.security/src/com/ibm/websphere/security/package-info.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2011,2018 IBM Corporation and others.
2+
* Copyright (c) 2011, 2026 IBM Corporation and others.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License 2.0
55
* which accompanies this distribution, and is available at
@@ -11,7 +11,7 @@
1111
* IBM Corporation - initial API and implementation
1212
*******************************************************************************/
1313
/**
14-
* @version 1.2.0
14+
* @version 1.3.0
1515
*/
16-
@org.osgi.annotation.versioning.Version("1.2.0")
16+
@org.osgi.annotation.versioning.Version("1.3.0")
1717
package com.ibm.websphere.security;

dev/com.ibm.ws.security.registry/src/com/ibm/ws/security/registry/UserRegistry.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import java.rmi.RemoteException;
1616
import java.security.cert.X509Certificate;
1717
import java.util.List;
18+
import java.util.Map;
19+
import java.util.Set;
1820

1921
/**
2022
* Defines read-only API contract for UserRegistry implementations.
@@ -282,4 +284,45 @@ public SearchResult getUsersForGroup(String groupSecurityName,
282284
**/
283285
List<String> getGroupsForUser(String userSecurityName) throws EntryNotFoundException, RegistryException;
284286

287+
/**
288+
* Returns the attributes for <i>userSecurityName</i>.
289+
*
290+
* @param userSecurityName the name of the user.
291+
* @param attributeNames
292+
* @return a Map of attributes for the user.
293+
* <code>null</code> is not returned.
294+
* @exception EntryNotFoundException if userSecurityName does not exist or is not unique.
295+
* @exception RegistryException if there is any UserRegistry specific problem
296+
* @exception IllegalArgumentException if userSecurityName is <code>null</code> or empty
297+
**/
298+
@Deprecated
299+
default Map<String, Object> getAttributesForUser(String userSecurityName, Set<String> attributeNames) throws EntryNotFoundException, RegistryException, NotImplementedException {
300+
throw new NotImplementedException("Reading user attributes is not supported.");
301+
}
302+
303+
/**
304+
* Gets a list of users that match an <i>attributeName</i> with specified
305+
* <i>value</i> in the UserRegistry.
306+
* The maximum number of users returned is defined by the <i>limit</i>
307+
* argument. This is very useful in situations where there are thousands of
308+
* users in the UserRegistry and getting all of them at once is not
309+
* practical.
310+
*
311+
* @param attributeName the attributeName to match.
312+
* @param value the value of the attributeName to match.
313+
* @param limit the maximum number of users that should be returned.
314+
* A value of 0 implies get all the users.
315+
* Specifying a negative value returns an empty SearchResult.
316+
* @return a <i>SearchResult</i> object that contains the list of users
317+
* requested and a flag to indicate if more users exist.
318+
* <code>null</code> is not returned.
319+
* @exception RegistryException if there is any UserRegistry specific problem
320+
* @exception IllegalArgumentException if attributeName is <code>null</code> or empty
321+
* @exception IllegalArgumentException if value is <code>null</code> or empty
322+
**/
323+
@Deprecated
324+
default SearchResult getUsersByAttribute(String attributeName, String value, int limit) throws RegistryException, NotImplementedException {
325+
throw new NotImplementedException("Reading user from attributes is not supported.");
326+
}
327+
285328
}

dev/com.ibm.ws.security.registry/src/com/ibm/ws/security/registry/internal/UserRegistryWrapper.java

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2012 IBM Corporation and others.
2+
* Copyright (c) 2012, 2026 IBM Corporation and others.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License 2.0
55
* which accompanies this distribution, and is available at
@@ -15,7 +15,9 @@
1515
import java.rmi.RemoteException;
1616
import java.security.cert.X509Certificate;
1717
import java.util.List;
18+
import java.util.Map;
1819
import java.util.Properties;
20+
import java.util.Set;
1921

2022
import com.ibm.websphere.ras.annotation.Sensitive;
2123
import com.ibm.websphere.security.CertificateMapFailedException;
@@ -290,4 +292,37 @@ public Result getUsersForGroup(String groupSecurityName, int limit) throws NotIm
290292
public WSCredential createCredential(String userSecurityName) throws NotImplementedException, EntryNotFoundException, CustomRegistryException, RemoteException {
291293
throw new NotImplementedException("The createCredential method is not available");
292294
}
295+
296+
@Override
297+
public Map<String, Object> getAttributesForUser(String userSecurityName, Set<String> attributeNames) throws EntryNotFoundException, CustomRegistryException, NotImplementedException {
298+
try {
299+
return wrappedUr.getAttributesForUser(userSecurityName, attributeNames);
300+
} catch (RegistryException e) {
301+
throw new CustomRegistryException(e.getMessage(), e);
302+
} catch (com.ibm.ws.security.registry.EntryNotFoundException e) {
303+
throw new EntryNotFoundException(e.getMessage(), e);
304+
} catch (com.ibm.ws.security.registry.NotImplementedException e) {
305+
throw new NotImplementedException(e.getMessage(), e);
306+
}
307+
308+
}
309+
310+
@Override
311+
public Result getUsersByAttribute(String attributeName, String value, int limit) throws CustomRegistryException, NotImplementedException {
312+
try {
313+
SearchResult ret = wrappedUr.getUsersByAttribute(attributeName, value, limit);
314+
Result result = new Result();
315+
result.setList(ret.getList());
316+
if (ret.hasMore()) {
317+
result.setHasMore();
318+
}
319+
return result;
320+
321+
} catch (RegistryException e) {
322+
throw new CustomRegistryException(e.getMessage(), e);
323+
} catch (com.ibm.ws.security.registry.NotImplementedException e) {
324+
throw new NotImplementedException(e.getMessage(), e);
325+
}
326+
}
327+
293328
}

dev/com.ibm.ws.security.registry/src/com/ibm/ws/security/registry/internal/package-info.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2011 IBM Corporation and others.
2+
* Copyright (c) 2011, 2026 IBM Corporation and others.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License 2.0
55
* which accompanies this distribution, and is available at
@@ -12,9 +12,9 @@
1212
*******************************************************************************/
1313

1414
/**
15-
* @version 1.0
15+
* @version 1.1.0
1616
*/
17-
@org.osgi.annotation.versioning.Version("1.0")
17+
@org.osgi.annotation.versioning.Version("1.1.0")
1818
@TraceOptions(traceGroup = TraceConstants.TRACE_GROUP, messageBundle = TraceConstants.MESSAGE_BUNDLE)
1919
package com.ibm.ws.security.registry.internal;
2020

dev/com.ibm.ws.security.registry/src/com/ibm/ws/security/registry/package-info.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2011 IBM Corporation and others.
2+
* Copyright (c) 2011, 2026 IBM Corporation and others.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License 2.0
55
* which accompanies this distribution, and is available at
@@ -12,9 +12,9 @@
1212
*******************************************************************************/
1313

1414
/**
15-
* @version 1.0
15+
* @version 1.1.0
1616
*/
17-
@org.osgi.annotation.versioning.Version("1.0")
17+
@org.osgi.annotation.versioning.Version("1.1.0")
1818
@TraceOptions(traceGroup = "UserRegistry", messageBundle = "com.ibm.ws.security.registry.internal.resources.LoggingMessages")
1919
package com.ibm.ws.security.registry;
2020

dev/com.ibm.ws.security.registry_test.servlet/src/com/ibm/ws/security/registry/test/UserRegistryServletConnection.java

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2011,2018 IBM Corporation and others.
2+
* Copyright (c) 2011, 2026 IBM Corporation and others.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License 2.0
55
* which accompanies this distribution, and is available at
@@ -25,7 +25,10 @@
2525
import java.security.PrivilegedExceptionAction;
2626
import java.security.cert.X509Certificate;
2727
import java.util.ArrayList;
28+
import java.util.HashMap;
2829
import java.util.List;
30+
import java.util.Map;
31+
import java.util.Set;
2932
import java.util.logging.Level;
3033
import java.util.logging.Logger;
3134

@@ -255,6 +258,35 @@ private List<String> convertToList(String methodName, String str) {
255258
}
256259
}
257260

261+
/**
262+
* @param methodName
263+
* @param str
264+
* @return
265+
*/
266+
private Map<String, Object> convertToMap(String methodName, String str) {
267+
/*
268+
* Something unlikely to occur in a DN, yet still readable. If this value changes
269+
* remember to update UserRegistryServlet#convertFromList() as well.
270+
*/
271+
final String delimiter = " :: ";
272+
273+
Map<String, Object> map = new HashMap<>();
274+
if (str.startsWith("{") && str.endsWith("}")) {
275+
if (str.length() == 2) {
276+
return map;
277+
} else {
278+
String[] contents = str.substring(1, str.length() - 1).split(delimiter);
279+
for (String entry : contents) {
280+
String[] mapEntry = entry.split("=");
281+
map.put(mapEntry[0], mapEntry[1]);
282+
}
283+
return map;
284+
}
285+
} else {
286+
throw new IllegalStateException(methodName + "expected {...}, but was: " + str);
287+
}
288+
}
289+
258290
/**
259291
* @param methodName
260292
* @param str
@@ -451,4 +483,25 @@ public String getType() {
451483
return makeServletMethodCall(methodName, servletRequest);
452484
}
453485

486+
/** {@inheritDoc} */
487+
@Override
488+
public Map<String, Object> getAttributesForUser(String userSecurityName, Set<String> attributeNames) throws EntryNotFoundException, RegistryException {
489+
String methodName = "getAttributesForUser";
490+
String servletRequest = "?method=" + methodName +
491+
"&userSecurityName=" + encodeForURI(userSecurityName) + "&attributeNames=" + String.join(",", attributeNames);
492+
String servletResponse = makeServletMethodCallWithExceptions(methodName, servletRequest);
493+
494+
return convertToMap(methodName, servletResponse);
495+
}
496+
497+
/** {@inheritDoc} */
498+
@Override
499+
public SearchResult getUsersByAttribute(String attributeName, String value, int limit) throws RegistryException {
500+
String methodName = "getUsersByAttribute";
501+
String servletRequest = "?method=" + methodName +
502+
"&attributeName=" + encodeForURI(attributeName) + "&value=" + value + "&limit=" + limit;
503+
String servletResponse = makeServletMethodCallWithException(methodName, servletRequest);
504+
505+
return convertToSearchResult(methodName, servletResponse);
506+
}
454507
}

dev/com.ibm.ws.security.registry_test.servlet/test-applications/userRegistry/src/web/UserRegistryServlet.java

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2011, 2021 IBM Corporation and others.
2+
* Copyright (c) 2011, 2026 IBM Corporation and others.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License 2.0
55
* which accompanies this distribution, and is available at
@@ -18,7 +18,10 @@
1818
import java.rmi.RemoteException;
1919
import java.security.AccessController;
2020
import java.security.PrivilegedAction;
21+
import java.util.Arrays;
2122
import java.util.List;
23+
import java.util.Map;
24+
import java.util.stream.Collectors;
2225

2326
import javax.servlet.Servlet;
2427
import javax.servlet.ServletException;
@@ -219,6 +222,18 @@ private void handleMethodRequest(HttpServletRequest req, PrintWriter pw, UserReg
219222
String groupSecurityName = req.getParameter("groupSecurityName");
220223
int limit = Integer.valueOf(req.getParameter("limit"));
221224
response = convertFromSR(ur.getUsersForGroup(groupSecurityName, limit));
225+
} else if ("getAttributesForUser".equals(method)) {
226+
String userSecurityName = req.getParameter("userSecurityName");
227+
String attributeNames = req.getParameter("attributeNames");
228+
response = convertFromMap(ur.getAttributesForUser(
229+
userSecurityName,
230+
Arrays.stream(attributeNames.split(",")).collect(Collectors.toSet())
231+
)).replaceAll("\n", "");
232+
} else if ("getUsersByAttribute".equals(method)) {
233+
String attributeName = req.getParameter("attributeName");
234+
String value = req.getParameter("value");
235+
int limit = Integer.parseInt(req.getParameter("limit"));
236+
response = convertFromSR(ur.getUsersByAttribute(attributeName, value, limit));
222237
} else {
223238
pw.println("Usage: url?method=name&paramName=paramValue&...");
224239
}
@@ -317,6 +332,38 @@ private static String convertFromList(List<?> results) {
317332
return sb.toString();
318333
}
319334

335+
private static String convertFromMap(Map<String, ?> map) {
336+
System.out.println("UserRegistryServlet.convertFromMap(): " + map.getClass() + " " + map);
337+
338+
if (map.isEmpty()) {
339+
return "{}";
340+
}
341+
342+
/*
343+
* Something unlikely to occur in a DN, yet still readable. If this value changes
344+
* remember to update UserRegistryServletConnection#convertToList() as well.
345+
*/
346+
final String delimiter = " :: ";
347+
348+
StringBuilder sb = new StringBuilder();
349+
sb.append('{');
350+
351+
int idx = 0;
352+
for (Map.Entry<String, ?> entry : map.entrySet()) {
353+
sb.append(entry.getKey());
354+
sb.append('=');
355+
sb.append(entry.getValue());
356+
357+
if (idx < map.size() - 1) {
358+
sb.append(delimiter);
359+
}
360+
idx++;
361+
}
362+
363+
sb.append('}');
364+
return sb.toString();
365+
}
366+
320367
/**
321368
* Create a DN safe string representation of a SearchResult. The problem with just
322369
* using the List.toString() method is that it separates entries by a ", ". That

0 commit comments

Comments
 (0)