/** * after a user has successfully logged in we want to build an access object for use in the * scheduling system * * @param String username * @param String group a group name to check for username in (via memberUid string) * @return boolean yes or no in the group * @throws NamingException when the search fails by DN this will be thrown */ private boolean userInGroup(String username, String group) throws NamingException { // assume they are not boolean inGroup = false; // Specify the attributes to match Attributes matchAttrs = new BasicAttributes(true); // ignore attribute name case // set the common name for the group using defined prefix ie 'cn' or 'ou' matchAttrs.put( new BasicAttribute( this.GROUPS_LOC.substring(0, this.GROUPS_LOC.indexOf("=")), group)); // named group for access rights // Search for objects that have those matching attributes in the specified group location NamingEnumeration answer = ctx.search(this.GROUPS_LOC + this.BASE_DN, matchAttrs); // search for that user id in the member list while (answer.hasMore()) { SearchResult sr = (SearchResult) answer.next(); if ((sr.getAttributes().get("memberuid").toString()).indexOf(username) >= 0) { // this user is in the specified group inGroup = true; } } System.err.println(username + " in " + group + ": " + new Boolean(inGroup).toString()); return inGroup; }
/* goodG2B() - use goodsource and badsink */ public void goodG2B_sink(String data, HttpServletRequest request, HttpServletResponse response) throws Throwable { Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://localhost:389"); DirContext ctx = new InitialDirContext(env); String search = "(cn=" + data + ")"; /* POTENTIAL FLAW: unsanitized data from untrusted source */ NamingEnumeration<SearchResult> answer = ctx.search("", search, null); while (answer.hasMore()) { SearchResult sr = answer.next(); Attributes a = sr.getAttributes(); NamingEnumeration<?> attrs = a.getAll(); while (attrs.hasMore()) { Attribute attr = (Attribute) attrs.next(); NamingEnumeration<?> values = attr.getAll(); while (values.hasMore()) { response.getWriter().println(" Value: " + values.next().toString()); } } } }
/* uses badsource and badsink - see how tools report flaws that don't always occur */ public void bad(HttpServletRequest request, HttpServletResponse response) throws Throwable { String data; if (IO.static_returns_t_or_f()) { Logger log_bad = Logger.getLogger("local-logger"); data = ""; /* init data */ /* retrieve the property */ Properties props = new Properties(); FileInputStream finstr = null; try { finstr = new FileInputStream("../common/config.properties"); props.load(finstr); data = props.getProperty("data"); } catch (IOException ioe) { log_bad.warning("Error with stream reading"); } finally { /* clean up stream reading objects */ try { if (finstr != null) { finstr.close(); } } catch (IOException ioe) { log_bad.warning("Error closing buffread"); } } } else { java.util.logging.Logger log_good = java.util.logging.Logger.getLogger("local-logger"); /* FIX: Use a hardcoded string */ data = "foo"; } Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://localhost:389"); DirContext ctx = new InitialDirContext(env); String search = "(cn=" + data + ")"; /* POTENTIAL FLAW: unsanitized data from untrusted source */ NamingEnumeration<SearchResult> answer = ctx.search("", search, null); while (answer.hasMore()) { SearchResult sr = answer.next(); Attributes a = sr.getAttributes(); NamingEnumeration<?> attrs = a.getAll(); while (attrs.hasMore()) { Attribute attr = (Attribute) attrs.next(); NamingEnumeration<?> values = attr.getAll(); while (values.hasMore()) { response.getWriter().println(" Value: " + values.next().toString()); } } } }
public Object getObjectInstance( Object obj, Name name, Context ctx, Hashtable<?, ?> env, Attributes inAttrs) throws Exception { if (obj instanceof DirContext) { Attribute objectClass = inAttrs.get("objectClass"); NamingEnumeration<?> ne = objectClass.getAll(); while (ne.hasMore()) { if (ne.next().equals("Service")) { return new Service(inAttrs); } } } return null; }
/* goodG2B1() - use goodsource and badsink by changing IO.staticTrue to IO.staticFalse */ private void goodG2B1() throws Throwable { String data; if (IO.staticFalse) { /* INCIDENTAL: CWE 561 Dead Code, the code below will never run * but ensure data is inititialized before the Sink to avoid compiler errors */ data = null; } else { /* FIX: Use a hardcoded string */ data = "foo"; } Hashtable<String, String> environmentHashTable = new Hashtable<String, String>(); environmentHashTable.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); environmentHashTable.put(Context.PROVIDER_URL, "ldap://localhost:389"); DirContext directoryContext = null; try { directoryContext = new InitialDirContext(environmentHashTable); /* POTENTIAL FLAW: data concatenated into LDAP search, which could result in LDAP Injection */ String search = "(cn=" + data + ")"; NamingEnumeration<SearchResult> answer = directoryContext.search("", search, null); while (answer.hasMore()) { SearchResult searchResult = answer.next(); Attributes attributes = searchResult.getAttributes(); NamingEnumeration<?> allAttributes = attributes.getAll(); while (allAttributes.hasMore()) { Attribute attribute = (Attribute) allAttributes.next(); NamingEnumeration<?> allValues = attribute.getAll(); while (allValues.hasMore()) { IO.writeLine(" Value: " + allValues.next().toString()); } } } } catch (NamingException exceptNaming) { IO.logger.log(Level.WARNING, "The LDAP service was not found or login failed.", exceptNaming); } finally { if (directoryContext != null) { try { directoryContext.close(); } catch (NamingException exceptNaming) { IO.logger.log(Level.WARNING, "Error closing DirContext", exceptNaming); } } } }
void exploreNext(int depth, DirContext ctx, String path) throws NamingException { NamingEnumeration<NameClassPair> names = ctx.list(path); while (names.hasMore()) { Object obj = names.next(); NameClassPair ncp = (NameClassPair) obj; if (ncp.getClassName().equals("weblogic.jndi.internal.ServerNamingNode")) { System.out.println(createBlanks(depth) + ncp.getName()); exploreNext(depth + 1, ctx, path + "/" + ncp.getName()); } else { System.out.print(createBlanks(depth) + "[" + ncp.getName()); System.out.print("] - "); try { // System.out.println(ctx.lookup(path+"/"+ncp.getName())); System.out.println(ncp.getClassName()); } catch (Exception ex) { System.out.println(""); } } } }
public void bad() throws Throwable { String data; badPrivate = true; data = bad_source(); Hashtable<String, String> environmentHashTable = new Hashtable<String, String>(); environmentHashTable.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); environmentHashTable.put(Context.PROVIDER_URL, "ldap://localhost:389"); DirContext directoryContext = null; try { directoryContext = new InitialDirContext(environmentHashTable); /* POTENTIAL FLAW: data concatenated into LDAP search, which could result in LDAP Injection */ String search = "(cn=" + data + ")"; NamingEnumeration<SearchResult> answer = directoryContext.search("", search, null); while (answer.hasMore()) { SearchResult searchResult = answer.next(); Attributes attributes = searchResult.getAttributes(); NamingEnumeration<?> allAttributes = attributes.getAll(); while (allAttributes.hasMore()) { Attribute attribute = (Attribute) allAttributes.next(); NamingEnumeration<?> allValues = attribute.getAll(); while (allValues.hasMore()) { IO.writeLine(" Value: " + allValues.next().toString()); } } } } catch (NamingException exceptNaming) { IO.logger.log(Level.WARNING, "The LDAP service was not found or login failed.", exceptNaming); } finally { if (directoryContext != null) { try { directoryContext.close(); } catch (NamingException exceptNaming) { IO.logger.log(Level.WARNING, "Error closing DirContext", exceptNaming); } } } }
/* goodG2B() - use goodsource and badsink by changing the "if" so that both branches use the GoodSource */ private void goodG2B(HttpServletRequest request, HttpServletResponse response) throws Throwable { String data; if (IO.static_returns_t_or_f()) { java.util.logging.Logger log_good = java.util.logging.Logger.getLogger("local-logger"); /* FIX: Use a hardcoded string */ data = "foo"; } else { java.util.logging.Logger log_good = java.util.logging.Logger.getLogger("local-logger"); /* FIX: Use a hardcoded string */ data = "foo"; } Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://localhost:389"); DirContext ctx = new InitialDirContext(env); String search = "(cn=" + data + ")"; /* POTENTIAL FLAW: unsanitized data from untrusted source */ NamingEnumeration<SearchResult> answer = ctx.search("", search, null); while (answer.hasMore()) { SearchResult sr = answer.next(); Attributes a = sr.getAttributes(); NamingEnumeration<?> attrs = a.getAll(); while (attrs.hasMore()) { Attribute attr = (Attribute) attrs.next(); NamingEnumeration<?> values = attr.getAll(); while (values.hasMore()) { response.getWriter().println(" Value: " + values.next().toString()); } } } }
/** * Print Attributes to System.out * * @param attrs */ private static void dump(Attributes attrs) { if (attrs == null) { System.out.println("No attributes"); } else { /* Print each attribute */ try { for (NamingEnumeration<? extends Attribute> ae = attrs.getAll(); ae.hasMore(); ) { Attribute attr = ae.next(); System.out.println("attribute: " + attr.getID()); /* print each value */ for (NamingEnumeration<?> e = attr.getAll(); e.hasMore(); System.out.println(" value: " + e.next())) ; } } catch (NamingException e) { e.printStackTrace(); } } } // dump
/** * Search for the user's entry. Determine the distinguished name of the user's entry and * optionally an authorization identity for the user. * * @param ctx an LDAP context to use for the search * @return the user's distinguished name or an empty string if none was found. * @exception LoginException if the user's entry cannot be found. */ private String findUserDN(LdapContext ctx) throws LoginException { String userDN = ""; // Locate the user's LDAP entry if (userFilter != null) { if (debug) { System.out.println( "\t\t[LdapLoginModule] " + "searching for entry belonging to user: "******"\t\t[LdapLoginModule] " + "cannot search for entry belonging to user: "******"Cannot find user's LDAP entry"); } try { NamingEnumeration results = ctx.search("", replaceUsernameToken(filterMatcher, userFilter), constraints); // Extract the distinguished name of the user's entry // (Use the first entry if more than one is returned) if (results.hasMore()) { SearchResult entry = (SearchResult) results.next(); // %%% - use the SearchResult.getNameInNamespace method // available in JDK 1.5 and later. // (can remove call to constraints.setReturningObjFlag) userDN = ((Context) entry.getObject()).getNameInNamespace(); if (debug) { System.out.println("\t\t[LdapLoginModule] found entry: " + userDN); } // Extract a value from user's authorization identity attribute if (authzIdentityAttr != null) { Attribute attr = entry.getAttributes().get(authzIdentityAttr); if (attr != null) { Object val = attr.get(); if (val instanceof String) { authzIdentity = (String) val; } } } results.close(); } else { // Bad username if (debug) { System.out.println("\t\t[LdapLoginModule] user's entry " + "not found"); } } } catch (NamingException e) { // ignore } if (userDN.equals("")) { throw (LoginException) new FailedLoginException("Cannot find user's LDAP entry"); } else { return userDN; } }
/* uses badsource and badsink */ public void bad() throws Throwable { String data; if (IO.staticTrue) { data = ""; /* Initialize data */ /* Read data using a listening tcp connection */ { ServerSocket listener = null; Socket socket = null; BufferedReader readerBuffered = null; InputStreamReader readerInputStream = null; /* Read data using a listening tcp connection */ try { listener = new ServerSocket(39543); socket = listener.accept(); /* read input from socket */ readerInputStream = new InputStreamReader(socket.getInputStream(), "UTF-8"); readerBuffered = new BufferedReader(readerInputStream); /* POTENTIAL FLAW: Read data using a listening tcp connection */ data = readerBuffered.readLine(); } catch (IOException exceptIO) { IO.logger.log(Level.WARNING, "Error with stream reading", exceptIO); } finally { /* Close stream reading objects */ try { if (readerBuffered != null) { readerBuffered.close(); } } catch (IOException exceptIO) { IO.logger.log(Level.WARNING, "Error closing BufferedReader", exceptIO); } try { if (readerInputStream != null) { readerInputStream.close(); } } catch (IOException exceptIO) { IO.logger.log(Level.WARNING, "Error closing InputStreamReader", exceptIO); } /* Close socket objects */ try { if (socket != null) { socket.close(); } } catch (IOException exceptIO) { IO.logger.log(Level.WARNING, "Error closing Socket", exceptIO); } try { if (listener != null) { listener.close(); } } catch (IOException exceptIO) { IO.logger.log(Level.WARNING, "Error closing ServerSocket", exceptIO); } } } } else { /* INCIDENTAL: CWE 561 Dead Code, the code below will never run * but ensure data is inititialized before the Sink to avoid compiler errors */ data = null; } Hashtable<String, String> environmentHashTable = new Hashtable<String, String>(); environmentHashTable.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); environmentHashTable.put(Context.PROVIDER_URL, "ldap://localhost:389"); DirContext directoryContext = null; try { directoryContext = new InitialDirContext(environmentHashTable); /* POTENTIAL FLAW: data concatenated into LDAP search, which could result in LDAP Injection */ String search = "(cn=" + data + ")"; NamingEnumeration<SearchResult> answer = directoryContext.search("", search, null); while (answer.hasMore()) { SearchResult searchResult = answer.next(); Attributes attributes = searchResult.getAttributes(); NamingEnumeration<?> allAttributes = attributes.getAll(); while (allAttributes.hasMore()) { Attribute attribute = (Attribute) allAttributes.next(); NamingEnumeration<?> allValues = attribute.getAll(); while (allValues.hasMore()) { IO.writeLine(" Value: " + allValues.next().toString()); } } } } catch (NamingException exceptNaming) { IO.logger.log(Level.WARNING, "The LDAP service was not found or login failed.", exceptNaming); } finally { if (directoryContext != null) { try { directoryContext.close(); } catch (NamingException exceptNaming) { IO.logger.log(Level.WARNING, "Error closing DirContext", exceptNaming); } } } }
/** * This method will test if a user has access to the LDAP, if so it will then check the list of * groups and check for is access * * @param String username as named via a uid in the LDAP * @param String password clear text in LDAP * @return Hashtable authenticate object */ public Hashtable authenticate(String username, String password, String keyfob_id) { Hashtable authHT = new Hashtable(); if (keyfob_id != null) { System.out.println("attempted keyfob value: " + keyfob_id); // we need to bind with our anon bind user username = this.AD_ANON_BIND_UNAME; password = this.AD_ANON_BIND_PWORD; } // assume they will not pass the test boolean authenticated = false; // first check to see if we even need to hit LDAP (not overridden) if (this.LDAP_OVERRIDE) { System.out.println("Override Authentication"); // just check against stored username/password, put in all groups if (username.equals(this.LDAP_OVERRIDE_UNAME) && password.equals(this.LDAP_OVERRIDE_PWORD)) { authenticated = true; // just add then to each group for (String key : groups.keySet()) { // push the name of the group and access to it boolean authHT.put(key, true); // method throws NamingException } } } else { // authenticate agianst creditials server System.err.println("Trying " + this.PROVIDER_TYPE + " authentication by: " + username); try { // build a hash table to pass as a bindable event // Set up environment for creating initial context Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, this.INITIAL_CONTEXT_FACTORY); env.put(Context.SECURITY_AUTHENTICATION, this.SECURITY_AUTHENTICATION); // we take the uid to authenticate, pair it with the username, and append the base location env.put(Context.PROVIDER_URL, this.PROVIDER_URL); if (this.PROVIDER_TYPE.equals("AD")) { env.put(Context.SECURITY_PRINCIPAL, username + "@" + this.AD_DOMAIN); } else if (this.PROVIDER_TYPE.equals("LDAP")) { env.put( Context.SECURITY_PRINCIPAL, "uid=" + username + "," + this.USERS_LOC + this.BASE_DN); } // we don't need to throw errors here because first try/catch finds it env.put(Context.SECURITY_CREDENTIALS, password); // send env assigments to console // enumerateContents(env.elements()); /** now that we have our hash values lets go authenticate */ // first we want to connect to the LDAP Server and create initial context // making sure the user name and password are valid ctx = new InitialDirContext( env); // Throws AuthenticationException if not valid username/password // WE NEVER GO PAST HERE IF AuthenticationException THROWN System.err.println("connection and creditials valid"); /** * we just split the two paths of AD and LDAP authentication because the LDAP way worked and * we are migrating to AD. However we want to be able to easily switch back until the LDAP * service is discontinued. Theoretically both services should be 'searchable' the same way * at some point the LDAP code should be removed or universal code written */ if (this.PROVIDER_TYPE.equals("AD")) { /** AD way, get the group list, if they match add */ SearchControls constraints = new SearchControls(); constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); // either search by user name or by keyfob id. either way will return a user if one is // found NamingEnumeration results = null; if (keyfob_id != null) { // we don't challenge on keyfob. assumed if you have keyfob you are that user System.out.println("searching for keyfob id: >" + keyfob_id + "<"); results = ctx.search( this.USERS_LOC + this.BASE_DN, "(" + this.ATTRIBUTE_NAME_KEYFOB_ID + "=" + keyfob_id + ")", constraints); authHT.put("keyfob_id", keyfob_id); // pass it back as proof positive we found it } else { results = ctx.search( this.USERS_LOC + this.BASE_DN, "(" + this.ATTRIBUTE_NAME_UNAME + "=" + username + ")", constraints); } while (results != null && results.hasMore()) { SearchResult sr = (SearchResult) results.next(); String dn = sr.getName() + ", " + this.USERS_LOC + this.BASE_DN; Attributes ar = ctx.getAttributes(dn, MY_ATTRS); if (ar == null) { // we need the user to have attributes throw new Exception("Entry " + dn + " has none of the specified attributes\n"); } for (int i = 0; i < MY_ATTRS.length; i++) { Attribute attr = ar.get(MY_ATTRS[i]); if (attr == null) { continue; } System.out.println(MY_ATTRS[i] + ":"); for (Enumeration vals = attr.getAll(); vals.hasMoreElements(); ) { String temp_next_element = vals.nextElement().toString(); // returns generic Object System.out.println("\t" + temp_next_element); // push the attributes to the auth HT if (!(authHT.containsKey(MY_ATTRS[i]))) { // push the name of the group and access to it boolean authHT.put(MY_ATTRS[i], temp_next_element); } // see if this element value matches any of my groups for (String key : groups.keySet()) { if (temp_next_element .toLowerCase() .startsWith("cn=" + groups.get(key).toLowerCase())) { // push the name of the group and access to it boolean authHT.put(key, true); // if user is found in ANY of the predefined groups they are 'authenticated' to // login. // RolemManager.as handles ACL authenticated = true; } } } } } // now for any groups not found, set them to false for (String key : groups.keySet()) { if (!(authHT.containsKey(key))) { // push the name of the group and access to it boolean authHT.put(key, false); } } // end AD WAY } else if (this.PROVIDER_TYPE.equals("LDAP")) { // authenticated only in the sense they are a valid AD user authenticated = true; // now that we have verified they are a valid user, lets see what type of access they have // groups are specified in the config file as "GROUP_<name>" key=value pairs where value // is the LDAP group name // and key is what we are looking for in the scheduling app for (String key : groups.keySet()) { // push the name of the group and access to it boolean authHT.put( key, new Boolean( userInGroup(username, groups.get(key)))); // method throws NamingException } } else { throw new Exception("Provider type not found."); } // Close the context when we're done ctx.close(); } catch (AuthenticationException e) { // binding to LDAP server with provided username/password failed // e.printStackTrace(); System.err.println( "AuthenticationException: " + e.getMessage()); // outputs -> [LDAP: error code 49 - Invalid Credentials] errorStack += e.getMessage() + "\n"; } catch (NamingException e) { // catches invalid DN. Should not be thrown unless changes made to DN // Could also fail from the context of the called method userInGroup System.err.println("NamingException: " + e.getMessage()); // e.printStackTrace(); errorStack += e.getMessage() + "\n"; } catch (Exception e) { e.printStackTrace(); System.err.println("Exception: " + e.getMessage()); errorStack += e.getMessage() + "\n"; } finally { // make sure our connection is closed if relevant if (ctx != null) { try { ctx.close(); } catch (NamingException e) { throw new RuntimeException(e); } } } } // push whether or not it was authenticated authHT.put("authenticated", new Boolean(authenticated)); // spill contents to catalina.out file enumerateContents(authHT.keys()); enumerateContents(authHT.elements()); return (authHT); }