I'm developing a web app that let users reset their own passwords in Active Directory. I've been doing it by binding as an administrator and it works fine, but the directory policies (reuse history, characters, etc) are not being enforced. I can't bind as a user because I don't have the current password.
I read about the LDAP_SERVER_POLICY_HINTS control introduced in Windows 2008 R2 SP1 for doing that in Active Directory and even found someone who made it using Spring LDAP
Since I'm using UnboundID and there is no standard control shipped for that, I figured that I had to create my own control class. The documented OID is 1.2.840.113556.1.4.2239 and the value {48, 3, 2, 1, 1}
public class PolicyHintsControl extends Control {
private static final long serialVersionUID = 1L;
public final static String LDAP_SERVER_POLICY_HINTS_OID = "1.2.840.113556.1.4.2066";
public final static byte[] LDAP_SERVER_POLICY_HINTS_DATA = { 48,
(byte) 132, 0, 0, 0, 3, 2, 1, 1 };
public PolicyHintsControl() {
super(LDAP_SERVER_POLICY_HINTS_OID, false, new ASN1OctetString(
LDAP_SERVER_POLICY_HINTS_DATA));
}
#Override
public String getControlName() {
return "LDAP Server Policy Hints Control";
}
#Override
public void toString(StringBuilder buffer) {
buffer.append("LDAPServerPolicyHints(isCritical=");
buffer.append(isCritical());
buffer.append(')');
}
}
So I added this new control in the modify request like this:
public static void main(String[] args) throws Exception {
final String host = "ldap.example.com";
final int port = 636;
String adminDn = "admin#example.com";
String adminPassword = "passwd";
String userDn = "CN=user,ou=people,dc=example,dc=com";
String userPassword = "passwd";
String keystoreFile = "/path/to/keystore.jks";
String keystorePassword = "passwd";
String passwordAttribute = "unicodePwd";
//Password change requires SSL
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(new FileInputStream(keystoreFile), keystorePassword.toCharArray());
TrustManagerFactory factory = TrustManagerFactory.getInstance("x509");
factory.init(keyStore);
final SSLUtil sslUtil = new SSLUtil(factory.getTrustManagers());
SSLSocketFactory socketFactory = sslUtil.createSSLSocketFactory();
Debug.setEnabled(true);
// Connect as the configured administrator
LDAPConnection ldapConnection = new LDAPConnection(socketFactory, host,
port, adminDn, adminPassword);
// Set password in AD format
final String newQuotedPassword = "\"" + userPassword + "\"";
final byte[] newPasswordBytes = newQuotedPassword.getBytes("UTF-16LE");
String encryptedNewPwd = new String(newPasswordBytes);
//Build modifications array and request
final ArrayList<Modification> modifications = new ArrayList<Modification>();
modifications.add(new Modification(ModificationType.REPLACE,
passwordAttribute, encryptedNewPwd));
ModifyRequest modifyRequest = new ModifyRequest(userDn, modifications);
//Add the policy hints control
modifyRequest.addControl(new PolicyHintsControl());
//Modify already
ldapConnection.modify(modifyRequest);
ldapConnection.close();
}
I get the following exception:
Exception in thread "main" LDAPException(resultCode=53 (unwilling to perform), errorMessage='0000052D: SvcErr: DSID-031A120C, problem 5003 (WILL_NOT_PERFORM), data 0
', diagnosticMessage='0000052D: SvcErr: DSID-031A120C, problem 5003 (WILL_NOT_PERFORM), data 0
')
After researching a bit more I found that there was another update in Windows 2012 for the same control which changed the OID to 1.2.840.113556.1.4.2066 and deprecated the old OID.
Since this app can be configured with any version of AD I'd like to handle gracefully every scenario (Windows 2012, Windows 2008 R2 SP1, others). My questions are:
Does anyone have successfully done this with UnboundID?
Is there anyway to know if the controls are available before the modification request?
What would be the best way to handle different OID's for different versions of AD for the same control? Same class or different classes?
I'm not all that familiar with Microsoft-specific controls so I can't provide a lot of help there, but it looks like you're already on the right track with that. In this case, it actually looks like the control is working as expected and the server is rejecting the password because it's not strong enough.
Active Directory is really awful with how hard it makes it to figure things like this out, but the secret lies in the "0000052D" given in the diagnostic message. That is a reference to Active Directory system error code 0x52D, which is decimal 1325. System error codes are documented at http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx, and in this case you need to follow the "System Error Codes (1300-1699)" link (http://msdn.microsoft.com/en-us/library/windows/desktop/ms681385(v=vs.85).aspx) and find the description for value 1325. The text for that error code says "Unable to update the password. The value provided for the new password does not meet the length, complexity, or history requirements of the domain." Since the point of the control you're trying to use seems to be to cause the server to perform quality checking on the new password, it looks like it's working as expected. If you use a stronger password (e.g., make it longer, include uppercase/numeric/symbol characters, etc.) then perhaps the server will accept it.
With regard to your question about figuring out what controls the server supports, the way to do that is to retrieve the server root DSE and look at the OIDs reported in the supportedControls attribute. The UnboundID LDAP SDK for Java makes this pretty easy because you can use the LDAPConnection.getRootDSE method to retrieve the root DSE, and then the RootDSE.supportsControl method to determine whether the server supports the specified control.
With regard to your question about whether to handle different OIDs with the same class or different classes, that's more a matter of style than anything else. If the control with the newer OID also uses a different encoding for the value, then that would definitely suggest making a separate class. If the value encoding is the same for both OIDs, then it's probably a matter of personal preference but even if you make them separate classes then it would be good to keep the majority of the code common rather than having the same code in two different places.
Related
This is a banking system and I have to create two user levels, Manager and Cashier. I have to provide username and password for manager and manager has to provide username and password for a cashier. I am not really sure how to code validation for cahsier login. This has to be coded in Java in Netbeans IDE (GUI)
My point is just a concern as your question needs you to have a basic understanding of Java. I am not sure whether you are storing your login details in a database or in a text file. If you store the data in a database, then you can just use the normal java validation techniques described below:
Get a username and a password from the cashier.
Select the records that match the user name and password you've entered above from the database.
Print a message if the number of records that you match is zero.
Login the cashier if the entered records match the ones stored in the database.
Please refer to here for more information on connecting to the database and storing/retrieving user data using java.
Also, note that banking applications should be more secure and therefore the best practice is to store seeded hashes of the passwords and use a cryptographically strong hashing function.
In case you are saving your data in a text file, then you can refer to this sample code . You can read more about the Java Scanner Class here. You can also decide to use a map to map all users on registering and then just check the map to confirm the login details.
N/B: In all of these cases, check if the username and password fields are empty before you submit the details.
If this were a real application, you would store usernames and hashed-and-salted versions of the passwords on disk (or you would query them over a network), ideally using bcrypt, pbkdf2, or another strong and upgrade-able password-hashing scheme. There are multiple open-source libraries that implement those for you.
Since this appears to be a programming exercise, the question of how you store them is probably mandated by whoever wrote it, and security may therefore be minimal.
The easiest way (which is not secure at all) of implementing this is to keep a password file around. You could, for example, use something similar to the following code:
public class InsecurePasswordStore {
private Map<String, String> passwords = new HashMap<>();
public void setPassword(String user, String password) {
passwords.put(user, password);
}
public boolean isPasswordCorrect(String user, String password) {
return passwords.get(user) != null && passwords.get(user).equals(password);
}
public void save(File file) throws IOException {
try (PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(file)))) {
for (Map.Entry<String, String> e: passwords.entrySet()) {
writer.println(e.getKey());
writer.println(e.getValue());
}
}
}
public void load(File file) throws IOException {
passwords.clear();
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
boolean finished = false;
while ( ! finished) {
String user = reader.readLine();
String password = reader.readLine();
if (user == null || password == null) {
finished = true;
} else {
passwords.put(user, password);
}
}
}
}
public static void main(String[] args) throws IOException {
InsecurePasswordStore store = new InsecurePasswordStore();
File passwordFile = new File("secrets.txt");
// create initial password file before first run
store.setPassword("manager", "12345");
store.save(passwordFile);
// load file when the app is launched
store.load(passwordFile);
// check password for a user
String badGuess = "2345";
System.out.println("Is " + badGuess
+ " the correct password for the manager? " + store.isPasswordCorrect("manager", badGuess));
String goodGuess = "12345";
System.out.println("Is " + goodGuess
+ " the correct password for the manager? " + store.isPasswordCorrect("manager", goodGuess));
// if the password was correct, set another username-password pair
if (store.isPasswordCorrect("manager", goodGuess)) {
store.setPassword("cashier", "abcde");
}
store.save(passwordFile);
}
}
My answer is more a series of questions and suggestions to get you to think about how to do it. Also, I cannot be very specific because you have provided very little detail in your question.
Question 1, after your manager enters the cashier details, where do you store them? In memory? In a file? In a database? Something else?
Question 2, when validating the cashier login, why would you not validate the cashier details against that database/file/memory store? The answer is you should validate your cashier logins against the place where they are stored.
Also for whatever it is worth, you should never hardcode a logon (e.g. the manager) into an application (not even for testing). Why?
There is no way to get rid of it without releasing a new version of the software.
It is a security risk (because of reason 1).
If you do it in testing, it is entirely possible that you will forget to remove it before the code is released. Then reason 2 applies.
There is no need for it - you can simply "seed" your user store with a single record representing the manager's login and default password (ideally with a "password has expired" indication) in your distribution or if you have an installer, prompt the person doing the setup to create the manager login during the installation process.
Therefore, the way you validate the manager's credentials will be exactly the same as everybody else.
This will (should) have the advantage of a simpler program which will be easier to maintain.
And just in case, the way you tell the difference between the manager, the cashier, a supervisor or whatever other user types that you might have (or need in the future) is via a role. In your user data store have a field that define which role the user is in (e.g. manager, cashier etc). Another model is "muliple fields" where you indicate that a user has that role (and thus access to the associated function or not). For example, you might have manager, supervisor, cashier, backoffice etc roles. Then just put a true/false in your user record that indicates whether that user can access the functions associated with a particular role.
Finally, your program becomes simpler because your logic is now simply
if user has manager role then display manager menu
if user has supervisor role then display supervisor menu"
etc
Note that there is no else in the above psuedo code.
I thought about repurposing org.eclipse.jface.bindings.Scheme to store key bindings on a per user base:
String userName = "Bob";
BindingManager bindingManager = ((BindingService) PlatformUI.getWorkbench().getService(IBindingService.class)).getBindingManager();
Scheme scheme = bindingManager.getScheme(userName);
scheme.define(userName, "Scheme for user " + userName, DEFAULT_SCHEME);
bindingManager.setActiveScheme(scheme);
Which works well for some moments, but whenever the schemes get loaded from the preferences (e.g. via CommandPersistence#reRead) only the schemes defined in the plugin.xml will be read and everything else gets discarded.
Especially this method of the class BindingService is a problem:
public final void savePreferences(final Scheme activeScheme,
final Binding[] bindings) throws IOException {
// store everything in preferences, then read everything
// -> custom schemes get removed
BindingPersistence.write(activeScheme, bindings);
// now the removed (undefined) scheme gets set
bindingManager.setActiveScheme(activeScheme);
bindingManager.setBindings(bindings);
}
Since I can't really register all users via plugin.xml, how can I register schemes programmatically?
As a "solution", I just re-implemented the scheme for our use case:
String userName = "Bob";
String keyBindings = MyPlugin.getDefault().getPreferenceStore().getString("keyBindings." + userName);
PlatformUI.getPreferenceStore().setValue(PlatformUI.PLUGIN_ID + ".commands", keyBindings);
This triggers CommandPersistence#reRead as well, but since I don't have my custom scheme this time, it doesn't fail. Now the management of our different schemes is our problem, but at least that way it works.
Background
My application connects to the Genesys Interaction Server in order to receive events for actions performed on the Interaction Workspace. I am using the Platform SDK 8.5 for Java.
I make the connection to the Interaction Server using the method described in the API reference.
InteractionServerProtocol interactionServerProtocol =
new InteractionServerProtocol(
new Endpoint(
endpointName,
interactionServerHost,
interactionServerPort));
interactionServerProtocol.setClientType(InteractionClient.AgentApplication);
interactionServerProtocol.open();
Next, I need to register a listener for each Place I wish to receive events for.
RequestStartPlaceAgentStateReporting requestStartPlaceAgentStateReporting = RequestStartPlaceAgentStateReporting.create();
requestStartPlaceAgentStateReporting.setPlaceId("PlaceOfGold");
requestStartPlaceAgentStateReporting.setTenantId(101);
isProtocol.send(requestStartPlaceAgentStateReporting);
The way it is now, my application requires the user to manually specify each Place he wishes to observe. This requires him to know the names of all the Places, which he may not necessarily have [easy] access to.
Question
How do I programmatically obtain a list of Places available? Preferably from the Interaction Server to limit the number of connections needed.
There is a method you can use. If you check methods of applicationblocks you will see cfg and query objects. You can use it for get list of all DNs. When building query, try blank DBID,name and number.
there is a .net code similar to java code(actually exatly the same)
List<CfgDN> list = new List<CfgDN>();
List<DN> dnlist = new List<Dn>();
CfgDNQuery query = new CfgDNQuery(m_ConfService);
list = m_ConfService.RetrieveMultipleObjects<CfgDN>(query).ToList();
foreach (CfgDN item in list)
{
foo = (DN) item.DBID;
......
dnlist.Add(foo);
}
Note : DN is my class which contains some property from platform SDK.
KeyValueCollection tenantList = new KeyValueCollection();
tenantList.addString("tenant", "Resources");
RequestStartPlaceAgentStateReportingAll all = RequestStartPlaceAgentStateReportingAll.create(tenantList);
interactionServerProtocol.send(all);
I am using SSL connection with X509 certificates provided from smartcards.
I have 2 identical tokens from athena . I initialise the keystores after I am reading the certificates, but when I am trying to to do the actual connection for the second token I am getting no provider found for my Private key.Connecting using the first token it's not affected, it works.
I tried adding different SunPCKS11 provider by specifing the slotIndexList to 1 , the number for the second token given by "slots = p11.C_GetSlotList(true)", but still the same error.
When I am listing the providers: I see the second provider, but java doesn't use it (I don't know why).
Provider _etpkcs11;
slots = p11.C_GetSlotList(true);
if(slot ==0)
{
String pkcs11config = "name=Athena\nlibrary=C:\WINDOWS\system32\asepkcs.dll";
byte[] pkcs11configBytes =pkcs11config.getBytes();
ByteArrayInputStream configStream = new ByteArrayInputStream(pkcs11configBytes);
etpkcs11 = new SunPKCS11(configStream);
Security.addProvider(etpkcs11);
}
the above works
the following doesn't work
if(slot ==1)
{
String pkcs11config1 = "name=Athenaslot1\nlibrary=C:\WINDOWS\system32\asepkcs.dll";
byte[] pkcs11configBytes1 =pkcs11config1.getBytes();
ByteArrayInputStream configStream1 = new ByteArrayInputStream(pkcs11configBytes1);
etpkcs11 = new SunPKCS11(configStream1);
Security.addProvider(etpkcs11);
}
the following
for(int j=0;j<Security.getProviders().length;j++)
{
System.out.println(Security.getProviders()[j].getName());
}
returns:
SunPKCS11-Athena
SunPKCS11-Athenaslot1
SUN
SunRsaSign
SunEC
SunJSSE
SunJCE
SunJGSS
SunSASL
XMLDSig
SunPCSC
and the error when using the second the second token:
No installed provider supports this key: sun.security.pkcs11.P11Key$P11PrivateKey
Thanks
PS: I need the both tokens on same machine
After having a look at these docs it is saying that the instantiation of the SunPKCS11 can take a slot in the configuration.
So maybe you could try
String pkcs11config1 = "name=Athenaslot1\nslot=1\nlibrary=C:\WINDOWS\system32\asepkcs.dll";
Even though you add 2 providers to the list of providers, the SunPKCS11 class caches the first instance. It seems like it always uses this instance all the time. That's the reason your second provider is not picked up/identified.
You might have to write some sneaky code to approach your use case. Right before you use your second provider, you have to clear the cached instance. You can refer to this post here. It is unanswered, but the code you should be looking for is
Field moduleMapField = PKCS11.class.getDeclaredField("moduleMap");
moduleMapField.setAccessible(true);
Map<?, ?> moduleMap = (Map<?, ?>) moduleMapField.get(<YOUR_FIRST_PROVIDER_INSTANCE>);
moduleMap.clear(); // force re-execution of C_Initialize next time
What this basically does is clearing the cached instance. And now you can proceed to add your second provider instance to interact with your second token.
We have a project that uses HP Quality Center and one of the regular issues we face is people not updating comments on the defect.
So I was thinkingif we could come up with a small script or tool that could be used to periodically throw up a reminder and force the user to update the comments.
I came across the Open Test Architecture API and was wondering if there are any good Python or java examples for the same that I could see.
Thanks
Hari
Example of using Python (win32com) to connect to HP Quality Center via OTA
HP Quality Center exposes a com based API called OTA.
Documentation on this is downloadable from an QC server
(OTA_API_Reference.chm) (Weirdly it is very hard to find online)
The documentation uses VBScript (The officially supported internal language for QC)
and you will need to mentally translate to Python. THis is usually very simple, but
a couple of gotchas exist.
You will need to install on your machine the Quality Center local code, this is on your windows PC
if you have been able to get to QC through the web interface.
You will also need to know the URL of the server and you username and password and the domain
of the QC project you are working on.
from win32com.client import Dispatch
conn = get_QCConnection()
for bug in get_bugs(qcConn):
print bug.Title
put_QCConnection(conn)
#below code needs to be in seperate module or at least above the fold but here
# for clarity
def get_QCConnection():
'''Get the hardcoded connection to the server and domain.
Can be made a "real" engine if you try hard.
Use makepy utility to determine if the version number has changed (TDApiOle80)
but this works to current version'''
QCConnection = Dispatch("TDApiOle80.TDConnection")
url = "http://qc.example.com/qcbin"
QCConnection.InitConnectionEx(url)
QCConnection.login("USER", "PASS")
QCConnection.Connect("google_projects", "Google_Chrome")
return QCConnection
def put_QCConnection(qcConn):
#If one person logged in to QC changes *anything* on a bug,
# they hold a global lock on writing to that bug till
# thier session times out, so really really remember to logout
# its painful to wait for your own session to time out
qcConn.Logout()
def get_bugs(qcConn):
'''just following boiler plate from vbscript
PS the SetFilter is not in QTA API, it uses Filter.
But due to the workarounds in
the very brilliant pythoncom code it supplies a virtual wrapper class
called SetFilter - this is one of those gotchas '''
BugFactory = qcConn.BugFactory
BugFilter = BugFactory.Filter
BugFilter.SetFilter(u"Status", "New")
#NB - a lot of fields in QC are malleable - and vary from site to site.
#COntact your admins for a real list of fields you can adjust
buglist = BugFilter.NewList()
return buglist
This is not a bad basis for going forward, however I create a dummy class for defects and run something like:
dfcts = [defect(b) for b in buglist]
Then I can put worker code into defect class and keep things neater.
One thing you want to do is keep access to the raw qc bug internal to the python wrapper class.
Information for others who may view this thread.
To start all this You will need install pywin32, like from here http://sourceforge.net/projects/pywin32/files/pywin32/Build216/
First of all You will need to import pywin32
'''#author: www.qcintegration.com #mailto:contact#qcintegration.com'''
import pywintypes
import win32com.client as w32c
from win32com.client import gencache, DispatchWithEvents, constants
Then as second operation I include here action on login to server
def connect_server(qc, server):
'''Connect to QC server
input = str(http adress)
output = bool(connected) TRUE/FALSE '''
try:
qc.InitConnectionEx(server);
except:
text = "Unable connect to Quality Center database: '%s'"%(server);
return qc.Connected;
def connect_login(qc, username, password):
'''Login to QC server
input = str(UserName), str(Password)
output = bool(Logged) TRUE/FALSE '''
try:
qc.Login(username, password);
except pywintypes.com_error, err:
text = unicode(err[2][2]);
return qc.LoggedIn;
def connect_project(qc, domainname, projectname):
'''Connect to Project in QC server
input = str(DomainName), str(ProjectName)
output = bool(ProjectConnected) TRUE/FALSE '''
try:
qc.Connect(domainname, projectname)
except pywintypes.com_error, err:
text = "Repository of project '%s' in domain '%s' doesn't exist or is not accessible. Please contact your Site Administrator"%(projectname, domainname);
return qc.ProjectConnected;
Second of all method which will include OTAapi dll file
def qc_instance():
'''Create QualityServer instance under variable qc
input = None
output = bool(True/False)'''
qc= None;
try:
qc = w32c.Dispatch("TDApiole80.TDConnection");
text = "DLL QualityCenter file correctly Dispatched"
return True, qc;
except:
return False, qc;
Then main method to connect to QCserver
def qcConnect(server, username, password, domainname, projectname):
print("Getting QC running files");
status, qc = qc_instance();
if status:
print("Connecting to QC server");
if connect_server(qc, server):
##connected to server
print("Checking username and password");
if connect_login(qc, username, password):
print("Connecting to QC domain and project");
if connect_project(qc, domainname, projectname):
text = "Connected"
connected = True;
return connected, text;
else:
text = "Not connected to Project in QC server.\nPlease, correct DomainName and/or ProjectName";
connected = False;
return connected, text;
else:
text = "Not logged to QC server.\nPlease, correct UserName and/or Password";
connected = False;
return connected, text;
else:
text = "Not connected to QC server.\nPlease, correct server http address";
connected = False;
return connected, text;
else:
connected = False;
text = "Unable to find QualityCenter installation files.\nPlease connect first to QualityCenter by web page to install needed files"
return connected, text;
And at the end how to execute all of those methods in one place with example of use
if __name__ == "__main__":
server= r"http://qualitycenterServer:8080/qcbin"
username= "alex_qc"
password= ""
domainname= "DEFAULT"
projectname= "QualityCenter_Demo"
connection_status, text = qcConnect(server, username, password, domainname, projectname);
print "connection_status:", connection_status
In case of any more question mailto: contact#qcintegration.com
or directly to web side: http://www.qcintegration.com
I'm not sure there are any good samples for Java, because OTA can't be consumed by Java directly, it needs a Java to COM bridnge like JIntegra.
About Python, well you can use Python COM api's. And then any OTA example will do. You got plenty in QC documentation of OTA.
But I think the real question here is, why would you want to do it in Python or Java. Why not write what you need directly in QC using it's Workflow feature. Which will allow you to write your logic in VBScript, and have it invoked inside QC UI on user actions. For instance you can bind to the Post event of a Defect / Bug and check if there is a comment and if there is not prompt the user directly with a message.
There is a REST API to HPQC (ALM11 and newer) if you want to access it from Linux without running a Windows COM component.
Here is an example that pulls in a "requirement" record (# 1202) after authenticating.
import requests
session = requests.session()
user='hpqc'
password='xxxxx'
r = session.get("http://hpqc-server:8080/qcbin/authentication-point/authenticate",auth=(user,password))
r = session.get("http://hpqc-server:8080/qcbin/rest/domains/Foo/projects/Bar/requirements/1202")
print(r.text)
The parsing of r.text from XML is left as an exercise.
Though you have asked for a Python or Java based solution, sharing the following VBA code that you can use insde HPQC/ALM's script editor (Defects module script) to accomplish the goal.
Function Bug_FieldCanChange(FieldName, NewValue)
On Error Resume Next
if not changed then
strCommentBeforeUpdate = Bug_Fields("BG_DEV_COMMENTS").Value
end if
If FieldName = "BG_DEV_COMMENTS" and blnAddCommentClicked = False Then
Msgbox "Cannot update the comments." & Chr(13)& "Changes made will not be saved."&Chr(13)& "Please use 'Add comment' button to insert new comment." &Chr(13)& " Or click Cancel without saving."
blnUpdateCommentError = true
blnAddCommentClicked = False
changed = true
End If
Bug_FieldCanChange = DefaultRes
End Function
You can use a new Test and select type (VPXP_API) which allow script to run. The good thing there is that you'd have the function definition ready to be dragged from within QC instead of having to heavily rely on doc.
I've done an implementation in Python running some script from within QC still using its API but via a QC test which is handy to retrieve directly the result (Output) etc.. going through some shell command which can then call any script on any server etc...