First i want to explain what i want to do and how the code is looking:
I want to add a User via JNDI on my LDAP with JAVA, i added following code:
public void addUser(String firstName, String lastName, String number) throws NamingException {
Properties initialProperties = new Properties();
initialProperties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
initialProperties.put(Context.PROVIDER_URL, "***");
initialProperties.put(Context.SECURITY_AUTHENTICATION, "simple");
initialProperties.put(Context.SECURITY_PRINCIPAL, "***");
initialProperties.put(Context.SECURITY_CREDENTIALS, "***");
DirContext context = new InitialDirContext(initialProperties);
BasicAttributes attributes = new BasicAttributes();
Attribute attribute = new BasicAttribute("objectClass");
attribute.add("top");
attribute.add("person");
attribute.add("organizationalPerson");
attribute.add("inetOrgPerson");
Attribute sn = new BasicAttribute("sn");
Attribute cn = new BasicAttribute("cn");
sn.add(lastName);
cn.add(firstName);
attributes.put(sn);
attributes.put(cn);
attributes.put(attribute);
try {
context.createSubcontext("***", attributes);
} catch(NamingException e) {
e.printStackTrace();
}
}
When i call the method i get following error:
javax.naming.NoPermissionException: [LDAP: error code 50 - 00000005: SecErr: DSID-031528D2, problem 4003 (INSUFF_ACCESS_RIGHTS), data 0
Which makes no sense in my point of view because i created two other methods, one for getting all the users which works and one for editing a user which works too, so i have the rights to read and write a user, but when i want to create a user it says i have no permission ?
Do anyone else had this problem?
Is there any configuration on the Administrator user necessary on the LDAP? But the Administrator should be have all rights?
I hope anyone can help me! :)
Greetings,
Fabian.
so i have the rights to read and write a user, but when i want to create a user it says i have no permission
Read, write and create are 3 separate permissions. A user can have write permissions to existing objects, but not have permission to create a new object. Those permissions can be set differently on each OU.
Related
We've migrated from adal4j to msal4j in our java web applications.
All works well but the big difference is that when the user is already logged (maybe in other applications but same browser session) we always see the "select user" page and the user is not logged automatically and redirected to redirect uri as before with adal4j.
This is how we redirect to autentication page:
private static void redirectToAuthorizationEndpoint(IdentityContextAdapter contextAdapter) throws IOException {
final IdentityContextData context = contextAdapter.getContext();
final String state = UUID.randomUUID().toString();
final String nonce = UUID.randomUUID().toString();
context.setStateAndNonce(state, nonce);
contextAdapter.setContext(context);
final ConfidentialClientApplication client = getConfidentialClientInstance();
AuthorizationRequestUrlParameters parameters = AuthorizationRequestUrlParameters
.builder(props.getProperty("aad.redirectURI"), Collections.singleton(props.getProperty("aad.scopes"))).responseMode(ResponseMode.QUERY)
.prompt(Prompt.SELECT_ACCOUNT).state(state).nonce(nonce).build();
final String authorizeUrl = client.getAuthorizationRequestUrl(parameters).toString();
contextAdapter.redirectUser(authorizeUrl);
}
I've tried to remove .prompt(Prompt.SELECT_ACCOUNT)
but I receive an error
Any ideas?
• You might be getting the option for selecting the user account after switching to MSAL4J in your browser even after the SSO is enabled because either clearing the token cache is enabled in your code or MsalInteractionRequiredException option is thrown and specified accordingly due to which the application asks for a token interactively.
Thus, please check which accounts information is stored in the cache as below: -
ConfidentialClientApplication pca = new ConfidentialClientApplication.Builder(
labResponse.getAppId()).
authority(TestConstants.ORGANIZATIONS_AUTHORITY).
build();
Set<IAccount> accounts = pca.getAccounts().join(); ’
Then, from the above information, if you want to remove the accounts whose prompts you don’t want to see during the user account selection such that the default account should get selected and signed in automatically, execute the below code by modifying the required information: -
Set<IAccount> accounts = pca.getAccounts().join();
IAccount accountToBeRemoved = accounts.stream().filter(
x -> x.username().equalsIgnoreCase(
UPN_OF_USER_TO_BE_REMOVED)).findFirst().orElse(null);
pca.removeAccount(accountToBeRemoved).join();
• And for the MsalInteractiveRequiredException class in the code, kindly refer to the below official documentation link for the AcquireTokenSilently and other reasons responsible for the behaviour. Also, refer to the sample code given below for your reference regarding the same: -
https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-error-handling-java#msalinteractionrequiredexception
IAuthenticationResult result;
try {
ConfidentialClientApplication application =
ConfidentialClientApplication
.builder("clientId")
.b2cAuthority("authority")
.build();
SilentParameters parameters = SilentParameters
.builder(Collections.singleton("scope"))
.build();
result = application.acquireTokenSilently(parameters).join();
}
catch (Exception ex){
if(ex instanceof MsalInteractionRequiredException){
// AcquireToken by either AuthorizationCodeParameters or DeviceCodeParameters
} else{
// Log and handle exception accordingly
}
}
I need to check through LDAP if an ActiveDirectory user has the PASSWD_CANT_CHANGE flag set. I found the UserAccountControl attribute (https://learn.microsoft.com/it-it/windows/desktop/ADSchema/a-useraccountcontrol): it works for all other flags but it doesn't work for this flag. I only need to read it, not to write.
I'm using Java with UnboundID LDAP SDK (https://ldap.com/unboundid-ldap-sdk-for-java/).
Here is my JUnit test code.
public static enum UACFlags {
SCRIPT(0x0001),
ACCOUNTDISABLE(0x0002),
HOMEDIR_REQUIRED(0x0008),
LOCKOUT(0x0010),
PASSWD_NOTREQD(0x0020),
PASSWD_CANT_CHANGE(0x0040),
ENCRYPTED_TEXT_PWD_ALLOWED(0x0080),
TEMP_DUPLICATE_ACCOUNT(0x0100),
NORMAL_ACCOUNT(0x0200),
INTERDOMAIN_TRUST_ACCOUNT(0x0800),
WORKSTATION_TRUST_ACCOUNT(0x1000),
SERVER_TRUST_ACCOUNT(0x2000),
DONT_EXPIRE_PASSWORD(0x10000),
MNS_LOGON_ACCOUNT(0x20000),
SMARTCARD_REQUIRED(0x40000),
TRUSTED_FOR_DELEGATION(0x80000),
NOT_DELEGATED(0x100000),
USE_DES_KEY_ONLY(0x200000),
DONT_REQ_PREAUTH(0x400000),
PASSWORD_EXPIRED(0x800000),
TRUSTED_TO_AUTH_FOR_DELEGATION(0x1000000);
private int flag;
private UACFlags(int flag) {
this.flag = flag;
}
}
#Test
public void testLDAP() throws LDAPException {
LDAPConnection connection = //GET CONNECTION
String username = "....";
String search = "(sAMAccountName=" + username + ")";
SearchRequest request = new SearchRequest("DC=....,DC=....", SearchScope.SUB, search, SearchRequest.ALL_USER_ATTRIBUTES);
SearchResult result = connection.search(request);
SearchResultEntry entry = result.getSearchEntries().get(0);
Attribute a = entry.getAttribute("userAccountControl");
int val = a.getValueAsInteger();
System.out.println(Integer.toHexString(val));
EnumSet<UACFlags> flags = EnumSet.noneOf(UACFlags.class);
for (UACFlags f : UACFlags.values()) {
if ((val & f.flag) == f.flag) {
flags.add(f);
}
}
System.out.println("FLAGS: " + flags);
}
I set up the flag on AD Users and Computers and it works as expected. I only want to check the flag programmatically, using Java and LDAP. Other solutions than UserAccountControl attribute are ok!
Thanks!!
That is, unfortunately, expected.
Microsoft uses the ADS_USER_FLAG_ENUM enumeration in a couple places:
The userAccountControl attribute when using LDAP, and
The userFlags property when using the WinNT provider.
The ADS_UF_PASSWD_CANT_CHANGE flag can only be used when using the WinNT provider, which I'm not sure you can do from Java.
When you click that 'User cannot change password' checkbox in AD Users and Computers, it doesn't actually change the userAccountControl attribute. In reality, it adds two permissions on the account:
Deny Change Password to 'Everyone'
Deny Change Password to 'SELF'
There is a description of how to look for those permissions here, but the examples are in C++ and VBScript. I don't know how to view the permissions in Java. It seems difficult and I can't find any real examples.
UPDATE
Appears from AD 2008 on that this is not a "real" value; but rather an ACE within the ACL of the entry.
THIS NO LONGER WORKS
As far as I can tell.
Microsoft Active Directory has a neat Extensible matching value that should work called LDAP_MATCHING_RULE_BIT_AND
So a simple LDAP Query Filter like:
(userAccountControl:1.2.840.113556.1.4.803:=64)
Should do the trick.
we required to fetch all user of dynamic group from LDAP server in Our Java based application.
below is my dynamic group url:
ldap:///ou=testou,o=test.com??sub?(&(|(atype=*Abc Company*)(atype=*def Company*)(ctype=test))(enabled=1)(!(sgroup=*testgrp*))(!(|(op=ABC)(bdesc=*abcdef*))))
when i provided filter from above url in JXplore, i am able to get user group which is available in this dynamic group but when i provide same filter in below java code LDAP is not returning any result. If i provided simple filter like cn=a* then it is working and LDAP is returning results.
public static void main(String[] args) throws NamingException, IOException {
Properties env = new Properties();
env.put("java.naming.factory.initial",
"com.sun.jndi.ldap.LdapCtxFactory");
// LDAP url
env.put("java.naming.provider.url", "url");
env.put("com.sun.jndi.ldap.read.timeout", "1000");
// ldap login
env.put("java.naming.security.principal", "username");
env.put("java.naming.security.credentials", "password");
InitialLdapContext ctx = new InitialLdapContext(env, null);
String contextName = "ou=testou,o=test.com";
// Filter expression
String filterExpr = "(&(|(atype=*Abc Company*)(atype=*def Company*)(ctype=test))(enabled=1)(!(sgroup=*testgrp*))(!(|(op=ABC)(bdesc=*abcdef*))))"; // selects the groups a user belongs to.
SearchControls constraints = new javax.naming.directory.SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); // SUBTREE_SCOPE means recursive search
ctx.setRequestControls(new Control[]{new PagedResultsControl(1000,true)});
byte[] cookie = null;
int totalResults = 0;
NamingEnumeration<SearchResult> search = ctx.search(contextName,
filterExpr,constraints);
int count=0;
while (search.hasMoreElements()) {
count++;
System.out.println(search.next().getName());
}
System.out.println("Total user"+count);
}
Assuming you are talking about JNDI, sadly the JNDI Tutorial, p. 247, says:
Note: Version 1.2 of Sun's LDAP provider does not treat query components properly
and nothing appears to have changed in any release up to Java 8.
The Dynamic Groups feature relies on this.
Ok, this is driving me crazy. I'm trying to create an LDAP authentication with Java and everything is fine if I use my First name and Last name in the SECURITY_PRINCIPAL. This is my code:
try {
Hashtable<String, String> ldapEnv = new Hashtable<String, String>();
ldapEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
ldapEnv.put(Context.PROVIDER_URL, "LDAP://myldap.mydomain.com:389");
ldapEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
ldapEnv.put(Context.SECURITY_PRINCIPAL, "CN=FirstName LastName" + ",ou=Users");
ldapEnv.put(Context.SECURITY_CREDENTIALS, "password");
DirContext ldapContext = new InitialLdapContext(ldapEnv, null);
}
catch (Exception e) {
System.out.println(" bind error: " + e);
e.printStackTrace();
}
The problem is that it does not work with my username. If I try:
ldapEnv.put(Context.SECURITY_PRINCIPAL, "CN=myusername" + ",ou=Users");
Or
ldapEnv.put(Context.SECURITY_PRINCIPAL, "uid=myusername" + ",ou=Users");
I always get [LDAP: error code 49 - 80090308: LdapErr: DSID-0C0903A9, comment: AcceptSecurityContext error, data 52e, v1db1]
This only seems to work with my First name and Last name for some reason. I checked the AD and my sAMAccountName is my correct username. Not sure why this is happening. Anyone else had such issues? Can I pass something else to Context.SECURITY_PRINCIPAL? I tried ldapEnv.put(Context.SECURITY_PRINCIPAL, "sAMAccountName=myusername" + ",ou=Users"); but it also fails... Can anyone please help?
EJP, thanks for your input. You are indeed correct but I was looking for something simple - just pass a username and password to the AD and see if it authenticates or not .I should have been more specific in my first post. Your suggestion will work but I think this is much simpler:
Hashtable props = new Hashtable();
String principalName = "username#mydomain.com";
props.put(Context.SECURITY_PRINCIPAL, principalName);
props.put(Context.SECURITY_CREDENTIALS, "mypassword");
DirContext context;
//try to authenticate
try {
context = com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance("LDAP://myldap.mydomain.com:389" + '/', props);
context.close();
}
This way I don't care about the DN. Just passing the username#domain and voila - works like a charm :) Thanks again!
There is no entry whose DN contains a UID or CN=username. You have to provide an entry which exists, not just an arbitrary string of attributes. The usual technique is to bind as an admin user, search for the user who has that UID or whatever he provided to your login system, retrieve the DN of that user, then try to bind as that DN with the user-supplied password.
I am trying to grant permission to a group on a folder in Perforce. However, the permission table that is created/updated from Java in Perforce is empty.
Following are the steps that I do -
//Get the server object.
IOptionsServer server = ServerFactory.getOptionsServer("p4java://<ip>:1666", null);
server.connect();
server.setUserName("<username>"); // this is a super user
server.login("<password>");
//Create a user group and add users.
IUserGroup ug = new UserGroup();
String groupName = "<usergroup_somename>;
ug.setName(groupName);
List<String> userList = new ArrayList<>();
userList.add("<username1>");
userList.add("<username2>");
userList.add("<username3>");
ug.setUsers(userList);
server.createUserGroup(ug);
//Get the permission table.
GetProtectionEntriesOptions gpo = new GetProtectionEntriesOptions();
gpo.setAllUsers(true);
List<IProtectionEntry> peList = server.getProtectionEntries(null, gpo);
//Create a new Protection entry
IProtectionEntry pe = new ProtectionEntry();
pe.setGroup(true);
pe.setName(groupName);
depotFilePath = "//depottest/Level1/Level2/..."; // the folders exist in Perforce
pe.setPath(depotFilePath);
pe.setMode("write");
pe.setHost("*");
pe.setPathExcluded(false);
pe.setOrder(peList.size());
pe.setType(EntryType.INCLUDE);
//Add the new created permission into the fetched Permission table list.
peList.add(pe);
//Create/Update the Permission table using either of the following methods separately or in combination creates a blank permission table.
server.createProtectionEntries(peList);
server.updateProtectionEntries(peList);
According to the documentation the methods in the end should create/replace/update the Permission table, however, this does not happen and instead the permission table in the Perforce server is deleted/blank.
I may be missing something. Can someone please give some suggestions on how to fix this?
P.S. I have tried using only the updateProtectionEntries(peList) method or the server.createProtectionEntries(peList) method and both together and still the pemission table in the Perforce server is blank.
Perforce has forums where you can ask questions: forums.perforce.com
At one time (depends on P4Java and server versions) incorrect order values could lose data. There's also a spaces-in-path problem.
This works for me:
peList.add(pe);
// fix order values and spaces-in-path quoting
int i = 0;
for (IProtectionEntry pe : peList) {
pe.setOrder(i++);
if (pe.getPath().indexOf(" ") >= 0) {
// this bug should be fixed in 2014.X (no promises)
if (pe.isPathExcluded()) {
pe.setPath("\"-" + pe.getPath() + "\"");
pe.setPathExcluded(false);
} else {
pe.setPath("\"" + pe.getPath() + "\"");
}
}
}
try {
String createProtectionEntries = server.createProtectionEntries(peList);