Revision 77:ab73820d251d
src/main/java/my/com/upass/MinimalUPassControllerV2.java | ||
---|---|---|
9 | 9 |
|
10 | 10 |
import my.com.upass.dao.ConfigurationDAO; |
11 | 11 |
import my.com.upass.dao.MinimalDAOFactory; |
12 |
import my.com.upass.maybank.entities.IbccUser; |
|
13 |
import my.com.upass.maybank.entities.Im2uUser; |
|
12 | 14 |
import my.com.upass.maybank.entities.M2uUser; |
13 | 15 |
import my.com.upass.maybank.entities.M2uUserContainer; |
14 | 16 |
import my.com.upass.maybank.entities.StockUser; |
17 |
import my.com.upass.maybank.entities.TicketingUser; |
|
15 | 18 |
import my.com.upass.maybank.entities.UserProfile; |
16 | 19 |
import my.com.upass.pojo.AuthenticationBean; |
17 | 20 |
import my.com.upass.pojo.ClientApp; |
... | ... | |
25 | 28 |
import my.com.upass.services.ModifyUserService; |
26 | 29 |
import my.com.upass.services.VerifyStaticPasswordService; |
27 | 30 |
import my.com.upass.services.VerifyStaticPasswordService.ReturnBundle; |
31 |
import my.com.upass.spring.ldap.MaybankLdapConstant; |
|
28 | 32 |
import my.com.upass.spring.ldap.MaybankLdapDAO; |
29 | 33 |
|
30 | 34 |
import org.apache.commons.lang.NotImplementedException; |
... | ... | |
405 | 409 |
} else if (invokingAppId.intValue() != appIdForProfile) { |
406 | 410 |
permitted = false; |
407 | 411 |
} |
408 |
if (permitted) |
|
412 |
if (permitted){
|
|
409 | 413 |
rc = updateProfileShallowly_noAccessCheck(profile, txSession); |
410 |
else
|
|
414 |
}else{
|
|
411 | 415 |
rc = MinimalConstants.ERR_APP_SERV_NOT_PERMITTED; |
416 |
} |
|
412 | 417 |
|
413 | 418 |
} catch (MultipleAppAccessesFound e) { |
414 | 419 |
rc = MinimalConstants.ERR_APP_SERV_NOT_PERMITTED; |
... | ... | |
423 | 428 |
|
424 | 429 |
final MinimalUserBean user = profile.getMinUser(); |
425 | 430 |
final String username = user.getUsername(); |
431 |
final String userPassword = user.getHashedPassword(); |
|
426 | 432 |
|
427 | 433 |
if (profile instanceof M2uUserContainer) { |
428 | 434 |
UserProfile m2uUser = findProfile_noAccessCheck(username, ClientApp.APP_ID_M2U, txSession); |
... | ... | |
439 | 445 |
: appAccessMgtService.grantAppAccessToUser( |
440 | 446 |
user.getUserID(), appIdForProfile, UserAppAccess.TYPE_USER, txSession); |
441 | 447 |
|
442 |
return granted ?
|
|
448 |
int rc = granted ?
|
|
443 | 449 |
modifyUserService.updateProfileShallowly(profile, txSession) |
444 | 450 |
: MinimalConstants.ERR_SYSTEM_NOT_READY; |
451 |
|
|
452 |
if (rc == MinimalConstants.ERR_SUCCESS && isInMigrationPeriod()) { |
|
453 |
Map attrMap = new HashMap(); |
|
454 |
String[] objectClasses = null; |
|
455 |
|
|
456 |
if(profile instanceof M2uUser){ |
|
457 |
objectClasses = new String[]{MaybankLdapConstant.OBJECT_CLASS_M2U}; |
|
458 |
|
|
459 |
if(!isEmptyString(((M2uUser)profile).getPan1())) |
|
460 |
attrMap.put(MaybankLdapConstant.ATTR_PAN_1, ((M2uUser)profile).getPan1()); |
|
461 |
if(!isEmptyString(((M2uUser)profile).getPan2())) |
|
462 |
attrMap.put(MaybankLdapConstant.ATTR_PAN_2, ((M2uUser)profile).getPan2()); |
|
463 |
|
|
464 |
} else if(profile instanceof Im2uUser){ |
|
465 |
objectClasses = new String[] { |
|
466 |
MaybankLdapConstant.OBJECT_CLASS_M2U, |
|
467 |
MaybankLdapConstant.OBJECT_CLASS_IM2U }; |
|
468 |
|
|
469 |
if(!isEmptyString(((Im2uUser)profile).getWsFlag())) |
|
470 |
attrMap.put(MaybankLdapConstant.ATTR_WS_FLAG, ((Im2uUser)profile).getWsFlag()); |
|
471 |
if(!isEmptyString(((Im2uUser)profile).getWsIdentCode())) |
|
472 |
attrMap.put(MaybankLdapConstant.ATTR_WS_IDENTCODE, ((Im2uUser)profile).getWsIdentCode()); |
|
473 |
if(!isEmptyString(((Im2uUser)profile).getWsMySgId())) |
|
474 |
attrMap.put(MaybankLdapConstant.ATTR_WS_MYSGID, ((Im2uUser)profile).getWsMySgId()); |
|
475 |
if(((Im2uUser)profile).getWsRegTimeStamp() != null) |
|
476 |
attrMap.put(MaybankLdapConstant.ATTR_WS_REGTIMESTAMP, Im2uUser.DATE_FORMAT.format(((Im2uUser)profile).getWsRegTimeStamp())); |
|
477 |
if(((Im2uUser)profile).getM2uUser() != null){ |
|
478 |
if(!isEmptyString(((Im2uUser)profile).getM2uUser().getPan1())) |
|
479 |
attrMap.put(MaybankLdapConstant.ATTR_PAN_1, ((Im2uUser)profile).getM2uUser().getPan1()); |
|
480 |
if(!isEmptyString(((Im2uUser)profile).getM2uUser().getPan2())) |
|
481 |
attrMap.put(MaybankLdapConstant.ATTR_PAN_2, ((Im2uUser)profile).getM2uUser().getPan2()); |
|
482 |
} |
|
483 |
|
|
484 |
} else if(profile instanceof TicketingUser){ |
|
485 |
objectClasses = new String[] { |
|
486 |
MaybankLdapConstant.OBJECT_CLASS_ONLINE_TICKETING, |
|
487 |
"person", "organizationalPerson", |
|
488 |
"inetOrgPerson" }; |
|
489 |
if(!isEmptyString(((TicketingUser)profile).getPayeeCode())){ |
|
490 |
attrMap.put(MaybankLdapConstant.ATTR_PAYEE_CODE, ((TicketingUser)profile).getPayeeCode()); |
|
491 |
attrMap.put("cn", username); |
|
492 |
attrMap.put("sn", username); |
|
493 |
attrMap.put("givenName", username); |
|
494 |
} |
|
495 |
|
|
496 |
} else if(profile instanceof StockUser){ |
|
497 |
objectClasses = new String[] { |
|
498 |
MaybankLdapConstant.OBJECT_CLASS_M2U, |
|
499 |
MaybankLdapConstant.OBJECT_CLASS_ONLINE_STOCK1, |
|
500 |
MaybankLdapConstant.OBJECT_CLASS_ONLINE_STOCK2 }; |
|
501 |
|
|
502 |
if(!isEmptyString(((StockUser)profile).getIdNo())){ |
|
503 |
attrMap.put(MaybankLdapConstant.ATTR_IDNO, ((StockUser)profile).getIdNo()); |
|
504 |
attrMap.put(MaybankLdapConstant.ATTR_CUST_TYPE, "0"); |
|
505 |
} |
|
506 |
|
|
507 |
if(((StockUser)profile).getM2uUser() != null){ |
|
508 |
if(!isEmptyString(((StockUser)profile).getM2uUser().getPan1())) |
|
509 |
attrMap.put(MaybankLdapConstant.ATTR_PAN_1, ((StockUser)profile).getM2uUser().getPan1()); |
|
510 |
if(!isEmptyString(((StockUser)profile).getM2uUser().getPan2())) |
|
511 |
attrMap.put(MaybankLdapConstant.ATTR_PAN_2, ((StockUser)profile).getM2uUser().getPan2()); |
|
512 |
} |
|
513 |
|
|
514 |
} else if(profile instanceof IbccUser){ |
|
515 |
objectClasses = new String[]{MaybankLdapConstant.OBJECT_CLASS_CCPP}; |
|
516 |
if(!isEmptyString(((IbccUser)profile).getPanCc())) |
|
517 |
attrMap.put(MaybankLdapConstant.ATTR_PANCC, ((IbccUser)profile).getPanCc()); |
|
518 |
} |
|
519 |
|
|
520 |
if (!attrMap.isEmpty()) { |
|
521 |
if(profile instanceof TicketingUser){ |
|
522 |
if(MinimalUPassControllerV2.getMaybankLdapDAO().isUserExist(username)){ |
|
523 |
MinimalUPassControllerV2.getMaybankLdapDAO().updateTicketingUser(username, attrMap); |
|
524 |
logger.info("Ticketing User updated in LDAP: " + username); |
|
525 |
}else{ |
|
526 |
MinimalUPassControllerV2.getMaybankLdapDAO().createTicketingUser(username, userPassword, objectClasses, attrMap); |
|
527 |
logger.info("Ticketing User created in LDAP: " + username); |
|
528 |
} |
|
529 |
}else{ |
|
530 |
if(MinimalUPassControllerV2.getMaybankLdapDAO().isUserExist(username)){ |
|
531 |
MinimalUPassControllerV2.getMaybankLdapDAO().updateUser(username, attrMap); |
|
532 |
logger.info("User updated in LDAP: " + username); |
|
533 |
}else{ |
|
534 |
MinimalUPassControllerV2.getMaybankLdapDAO().createUser(username, userPassword, objectClasses, attrMap); |
|
535 |
logger.info("User created in LDAP: " + username); |
|
536 |
} |
|
537 |
} |
|
538 |
} |
|
539 |
} |
|
540 |
|
|
541 |
return rc; |
|
445 | 542 |
} |
446 | 543 |
|
447 | 544 |
/** |
... | ... | |
749 | 846 |
} |
750 | 847 |
} |
751 | 848 |
|
849 |
private boolean isEmptyString(String value){ |
|
850 |
if(value == null) |
|
851 |
return true; |
|
852 |
|
|
853 |
if("".equals(value)) |
|
854 |
return true; |
|
855 |
|
|
856 |
return false; |
|
857 |
} |
|
752 | 858 |
} |
src/main/java/my/com/upass/maybank/MinimalMaybankFacadeImpl.java | ||
---|---|---|
1 | 1 |
package my.com.upass.maybank; |
2 | 2 |
|
3 |
import java.util.HashMap; |
|
4 | 3 |
import java.util.LinkedList; |
5 | 4 |
import java.util.List; |
6 | 5 |
import java.util.Map; |
... | ... | |
16 | 15 |
import my.com.upass.pojo.ClientApp; |
17 | 16 |
import my.com.upass.pojo.MinimalUserBean; |
18 | 17 |
import my.com.upass.pojo.UserAppAccess; |
19 |
import my.com.upass.spring.ldap.MaybankLdapConstant; |
|
20 | 18 |
|
21 | 19 |
import org.apache.log4j.Logger; |
22 | 20 |
import org.hibernate.Session; |
... | ... | |
258 | 256 |
|
259 | 257 |
rc = minUpcV2.addUser( |
260 | 258 |
appAccessId, hashedSecretKey, profile.getMinUser(), UserAppAccess.TYPE_USER, session); |
261 |
|
|
259 |
|
|
262 | 260 |
if (rc == MinimalConstants.ERR_SUCCESS) { |
263 | 261 |
rc = minUpcV2.updateProfileShallowly(appAccessId, hashedSecretKey, profile, session); |
264 |
|
|
265 |
if (rc == MinimalConstants.ERR_SUCCESS) |
|
262 |
|
|
263 |
if (rc == MinimalConstants.ERR_SUCCESS) {
|
|
266 | 264 |
session.getTransaction().commit(); |
267 |
else
|
|
265 |
} else {
|
|
268 | 266 |
GenericDAOHibernate.rollbackTransactionIfAny(session); |
269 |
|
|
270 |
} else |
|
267 |
} |
|
268 |
} else {
|
|
271 | 269 |
GenericDAOHibernate.rollbackTransactionIfAny(session); |
270 |
} |
|
272 | 271 |
|
273 | 272 |
} catch (UPassException e) { |
274 | 273 |
rc = e.getErrorCode(); |
... | ... | |
314 | 313 |
appAccessId, hashedSecretKey, m2uUser, session); |
315 | 314 |
|
316 | 315 |
if (rc == MinimalConstants.ERR_SUCCESS) { |
317 |
if (minUpcV2.isInMigrationPeriod()) { |
|
318 |
Map attrMap = new HashMap(); |
|
319 |
if (pan1 != null) |
|
320 |
attrMap.put(MaybankLdapConstant.ATTR_PAN_1, pan1); |
|
321 |
|
|
322 |
if (pan2 != null) |
|
323 |
attrMap.put(MaybankLdapConstant.ATTR_PAN_2, pan2); |
|
324 |
|
|
325 |
if (!attrMap.isEmpty()) |
|
326 |
MinimalUPassControllerV2.getMaybankLdapDAO().updateUser(username, attrMap); |
|
327 |
} |
|
328 | 316 |
session.getTransaction().commit(); |
329 | 317 |
|
330 | 318 |
} else { |
... | ... | |
388 | 376 |
} |
389 | 377 |
return res; |
390 | 378 |
} |
391 |
|
|
392 | 379 |
} |
src/main/java/my/com/upass/spring/ldap/MaybankLdapConstant.java | ||
---|---|---|
1 | 1 |
package my.com.upass.spring.ldap; |
2 | 2 |
|
3 |
|
|
3 | 4 |
public class MaybankLdapConstant { |
4 | 5 |
|
5 | 6 |
public static final String ATTR_USERID = "mbbuserid"; |
... | ... | |
7 | 8 |
public static final String ATTR_PAN_1 = "ibpan"; |
8 | 9 |
public static final String ATTR_PAN_2 = "ibpan2"; |
9 | 10 |
public static final String ATTR_IDNO = "IDNo"; |
11 |
public static final String ATTR_CUST_TYPE = "CustType"; |
|
12 |
public static final String ATTR_WS_FLAG = "wsFlag"; |
|
13 |
public static final String ATTR_WS_IDENTCODE = "wsIdentCode"; |
|
14 |
public static final String ATTR_WS_REGTIMESTAMP = "wsRegTimeStamp"; |
|
15 |
public static final String ATTR_WS_MYSGID = "wsMySgID"; |
|
16 |
public static final String ATTR_PAYEE_CODE = "PayeeCode"; |
|
17 |
public static final String ATTR_PANCC = "pancc"; |
|
18 |
|
|
19 |
public static final String OBJECT_CLASS_M2U = "internetbanking"; |
|
20 |
public static final String OBJECT_CLASS_ONLINE_STOCK1 = "onlinestockclass"; |
|
21 |
public static final String OBJECT_CLASS_ONLINE_STOCK2 = "tradingclass"; |
|
22 |
public static final String OBJECT_CLASS_ONLINE_TICKETING = "payeeobj"; |
|
23 |
public static final String OBJECT_CLASS_CCPP = "ibccpublic"; |
|
24 |
public static final String OBJECT_CLASS_IM2U = "wsm2uintegration"; |
|
25 |
|
|
10 | 26 |
} |
src/main/java/my/com/upass/spring/ldap/MaybankLdapDAO.java | ||
---|---|---|
13 | 13 |
|
14 | 14 |
public void updateUser(String mbbuserid, Map/*<String, String>*/ attributesMap) throws UPassException; |
15 | 15 |
|
16 |
public void updateTicketingUser(String mbbuserid, Map/*<String, String>*/ attributesMap) throws UPassException; |
|
17 |
|
|
18 |
public void createUser(String mbbuserid, String password, String[] objectClasses, Map/*<String, String>*/ attributesMap) throws UPassException; |
|
19 |
|
|
20 |
public void createTicketingUser(String mbbuserid, String password, String[] objectClasses, Map attributesMap) throws UPassException; |
|
21 |
|
|
22 |
/* |
|
23 |
* To be used in Load Test ONLY! |
|
24 |
*/ |
|
16 | 25 |
public int createUser(String mbbuserid, String password); |
17 | 26 |
|
27 |
/* |
|
28 |
* To be used in Load Test ONLY! |
|
29 |
*/ |
|
18 | 30 |
public int deleteUser(String mbbuserid); |
19 | 31 |
} |
src/main/java/my/com/upass/spring/ldap/MaybankLdapDAOImpl.java | ||
---|---|---|
25 | 25 |
private LdapTemplate ldapTemplate = null; |
26 | 26 |
private String base; |
27 | 27 |
private String usernameAttrName; |
28 |
private String baseTicketing; |
|
29 |
private String uidAttrName; |
|
28 | 30 |
|
29 | 31 |
public boolean isUserExist(String mbbuserid) { |
30 | 32 |
Object person = null; |
... | ... | |
37 | 39 |
|
38 | 40 |
if(person != null){ |
39 | 41 |
return true; |
42 |
} else { |
|
43 |
try { |
|
44 |
person = ldapTemplate.lookup(buildDnTicketing(mbbuserid)); |
|
45 |
} catch (NameNotFoundException e) { |
|
46 |
//not found |
|
47 |
} |
|
48 |
|
|
49 |
if(person != null){ |
|
50 |
return true; |
|
51 |
} |
|
40 | 52 |
} |
41 | 53 |
|
42 | 54 |
return false; |
43 | 55 |
} |
44 | 56 |
|
45 | 57 |
public boolean authenticate(String mbbuserid, String password) throws UPassException { |
46 |
boolean result = false;
|
|
58 |
boolean isSuccess = false;
|
|
47 | 59 |
try { |
48 |
result = ldapTemplate.authenticate(base, "(" + usernameAttrName + "=" + mbbuserid + ")", password); |
|
60 |
isSuccess = ldapTemplate.authenticate(base, "(" + usernameAttrName + "=" + mbbuserid + ")", password); |
|
61 |
if(!isSuccess){ |
|
62 |
isSuccess = ldapTemplate.authenticate(baseTicketing, "(" + uidAttrName + "=" + mbbuserid + ")", password); |
|
63 |
} |
|
49 | 64 |
|
50 | 65 |
} catch (NameNotFoundException e) { |
51 |
logger.warn("LDAP Error code:" + LdapStatusCodeParser.getCode(e.getExplanation()) |
|
52 |
+ " - " + e.getExplanation()); |
|
66 |
logger.warn("LDAP Error code:" + LdapStatusCodeParser.getCode(e.getExplanation()) + " - " + e.getExplanation()); |
|
53 | 67 |
throw new UPassException(MinimalConstants.ERR_LDAP); |
54 | 68 |
} |
55 |
if (!result) {
|
|
69 |
if (!isSuccess) {
|
|
56 | 70 |
logger.info("LDAP authentication failed!"); |
57 | 71 |
} |
58 |
return result;
|
|
72 |
return isSuccess;
|
|
59 | 73 |
} |
60 | 74 |
|
75 |
public void createUser(String mbbuserid, String password, String[] objectClasses, Map attributesMap) throws UPassException { |
|
76 |
Name dn = buildDn(mbbuserid); |
|
77 |
try { |
|
78 |
ldapTemplate.bind(dn, null, buildAttributes(mbbuserid, password, objectClasses, attributesMap)); |
|
79 |
} catch (org.springframework.ldap.NamingException e) { |
|
80 |
logger.warn("LDAP Error code:"+LdapStatusCodeParser.getCode(e.getExplanation()) + " - " + e.getExplanation()); |
|
81 |
throw new UPassException(MinimalConstants.ERR_LDAP); |
|
82 |
} |
|
83 |
} |
|
84 |
|
|
85 |
public void createTicketingUser(String mbbuserid, String password, String[] objectClasses, Map attributesMap) throws UPassException { |
|
86 |
Name dn = buildDnTicketing(mbbuserid); |
|
87 |
try { |
|
88 |
ldapTemplate.bind(dn, null, buildAttributes(mbbuserid, password, objectClasses, attributesMap)); |
|
89 |
} catch (org.springframework.ldap.NamingException e) { |
|
90 |
logger.warn("LDAP Error code:"+LdapStatusCodeParser.getCode(e.getExplanation()) + " - " + e.getExplanation()); |
|
91 |
throw new UPassException(MinimalConstants.ERR_LDAP); |
|
92 |
} |
|
93 |
} |
|
94 |
|
|
61 | 95 |
/** |
62 | 96 |
* To be used in Load Test ONLY! |
63 | 97 |
*/ |
... | ... | |
103 | 137 |
return attrs; |
104 | 138 |
} |
105 | 139 |
|
140 |
private Attributes buildAttributes(String mbbuserid, String password, String[] objectClasses, Map attributesMap) { |
|
141 |
Attributes attrs = new BasicAttributes(); |
|
142 |
BasicAttribute basicAttribute = new BasicAttribute("objectclass"); |
|
143 |
basicAttribute.add("top"); |
|
144 |
if(objectClasses != null && objectClasses.length > 0){ |
|
145 |
for(int i=0; i < objectClasses.length; i++){ |
|
146 |
basicAttribute.add(objectClasses[i]); |
|
147 |
} |
|
148 |
} |
|
149 |
attrs.put(basicAttribute); |
|
150 |
|
|
151 |
if(attributesMap != null && attributesMap.size() > 0){ |
|
152 |
Iterator it = attributesMap.entrySet().iterator(); |
|
153 |
while (it.hasNext()) { |
|
154 |
Map.Entry pairs = (Map.Entry)it.next(); |
|
155 |
attrs.put((String)pairs.getKey(), (String)pairs.getValue()); |
|
156 |
} |
|
157 |
} |
|
158 |
|
|
159 |
attrs.put("userPassword", password); |
|
160 |
|
|
161 |
return attrs; |
|
162 |
} |
|
163 |
|
|
106 | 164 |
public void updateUser(String mbbuserid, Map/*<String, String>*/ attributesMap) throws UPassException{ |
107 | 165 |
Name dn = buildDn(mbbuserid); |
108 | 166 |
DirContextOperations context = ldapTemplate.lookupContext(dn); |
... | ... | |
116 | 174 |
} |
117 | 175 |
} |
118 | 176 |
|
177 |
public void updateTicketingUser(String mbbuserid, Map/*<String, String>*/ attributesMap) throws UPassException{ |
|
178 |
Name dn = buildDnTicketing(mbbuserid); |
|
179 |
DirContextOperations context = ldapTemplate.lookupContext(dn); |
|
180 |
mapToContext(attributesMap, context); |
|
181 |
|
|
182 |
try { |
|
183 |
ldapTemplate.modifyAttributes(context); |
|
184 |
} catch (NamingException e) { |
|
185 |
logger.warn("LDAP Error code:"+LdapStatusCodeParser.getCode(e.getExplanation()) + " - " + e.getExplanation()); |
|
186 |
throw new UPassException(MinimalConstants.ERR_LDAP); |
|
187 |
} |
|
188 |
} |
|
189 |
|
|
119 | 190 |
protected void mapToContext(Map/*<String, String>*/ attributesMap, DirContextOperations context) { |
120 | 191 |
Iterator it = attributesMap.entrySet().iterator(); |
121 | 192 |
while (it.hasNext()) { |
... | ... | |
127 | 198 |
|
128 | 199 |
protected Name buildDn(String mbbuserid) { |
129 | 200 |
DistinguishedName dn = new DistinguishedName(base); |
130 |
dn.add("mbbuserid", mbbuserid); |
|
201 |
dn.add(usernameAttrName, mbbuserid); |
|
202 |
return dn; |
|
203 |
} |
|
204 |
|
|
205 |
protected Name buildDnTicketing(String uid) { |
|
206 |
DistinguishedName dn = new DistinguishedName(baseTicketing); |
|
207 |
dn.add(uidAttrName, uid); |
|
131 | 208 |
return dn; |
132 | 209 |
} |
133 | 210 |
|
... | ... | |
143 | 220 |
this.usernameAttrName = usernameAttrName; |
144 | 221 |
} |
145 | 222 |
|
223 |
public void setBaseTicketing(String baseTicketing) { |
|
224 |
this.baseTicketing = baseTicketing; |
|
225 |
} |
|
226 |
|
|
227 |
public void setUidAttrName(String uidAttrName) { |
|
228 |
this.uidAttrName = uidAttrName; |
|
229 |
} |
|
230 |
|
|
146 | 231 |
} |
src/main/resources/spring-ldap.xml | ||
---|---|---|
14 | 14 |
<property name="ldapTemplate" ref="ldapTemplate" /> |
15 | 15 |
<property name="base" value="ou=People,o=maybank"/> |
16 | 16 |
<property name="usernameAttrName" value="mbbuserid"/> |
17 |
<property name="baseTicketing" value="ou=WebLogic,o=maybank"/> |
|
18 |
<property name="uidAttrName" value="uid"/> |
|
17 | 19 |
</bean> |
18 | 20 |
</beans> |
Also available in: Unified diff