diff --git a/src/main/java/org/owasp/esapi/AccessControlRule.java b/src/main/java/org/owasp/esapi/AccessControlRule.java index b89af4e48..51458ff3b 100644 --- a/src/main/java/org/owasp/esapi/AccessControlRule.java +++ b/src/main/java/org/owasp/esapi/AccessControlRule.java @@ -2,7 +2,7 @@ public interface AccessControlRule { - void setPolicyParameters(P policyParameter); - P getPolicyParameters(); - boolean isAuthorized(R runtimeParameter) throws Exception; + void setPolicyParameters(P policyParameter); + P getPolicyParameters(); + boolean isAuthorized(R runtimeParameter) throws Exception; } diff --git a/src/main/java/org/owasp/esapi/AccessController.java b/src/main/java/org/owasp/esapi/AccessController.java index 15dfb5d7f..2aa8e84e0 100644 --- a/src/main/java/org/owasp/esapi/AccessController.java +++ b/src/main/java/org/owasp/esapi/AccessController.java @@ -66,70 +66,70 @@ */ public interface AccessController { - /** - * isAuthorized executes the AccessControlRule - * that is identified by key and listed in the - * resources/ESAPI-AccessControlPolicy.xml file. It returns - * true if the AccessControlRule decides that the operation - * should be allowed. Otherwise, it returns false. Any exception thrown by - * the AccessControlRule must result in false. If - * key does not map to an AccessControlRule, then - * false is returned. - * - * Developers should call isAuthorized to control execution flow. For - * example, if you want to decide whether to display a UI widget in the - * browser using the same logic that you will use to enforce permissions - * on the server, then isAuthorized is the method that you want to use. - * - * Typically, assertAuthorized should be used to enforce permissions on the - * server. - * - * @param key key maps to - * <AccessControlPolicy><AccessControlRules> - * <AccessControlRule name="key" - * @param runtimeParameter runtimeParameter can contain anything that - * the AccessControlRule needs from the runtime system. - * @return Returns true if and only if the AccessControlRule specified - * by key exists and returned true. - * Otherwise returns false - */ - boolean isAuthorized(Object key, Object runtimeParameter); - - /** - * assertAuthorized executes the AccessControlRule - * that is identified by key and listed in the - * resources/ESAPI-AccessControlPolicy.xml file. It does - * nothing if the AccessControlRule decides that the operation - * should be allowed. Otherwise, it throws an - * org.owasp.esapi.errors.AccessControlException. Any exception - * thrown by the AccessControlRule will also result in an - * AccesControlException. If key does not map to - * an AccessControlRule, then an AccessControlException - * is thrown. - * - * Developers should call {@code assertAuthorized} to enforce privileged access to - * the system. It should be used to answer the question: "Should execution - * continue." Ideally, the call to assertAuthorized should - * be integrated into the application framework so that it is called - * automatically. - * - * @param key key maps to - * <AccessControlPolicy><AccessControlRules> - * <AccessControlRule name="key" - * @param runtimeParameter runtimeParameter can contain anything that - * the AccessControlRule needs from the runtime system. - */ - void assertAuthorized(Object key, Object runtimeParameter) - throws AccessControlException; + /** + * isAuthorized executes the AccessControlRule + * that is identified by key and listed in the + * resources/ESAPI-AccessControlPolicy.xml file. It returns + * true if the AccessControlRule decides that the operation + * should be allowed. Otherwise, it returns false. Any exception thrown by + * the AccessControlRule must result in false. If + * key does not map to an AccessControlRule, then + * false is returned. + * + * Developers should call isAuthorized to control execution flow. For + * example, if you want to decide whether to display a UI widget in the + * browser using the same logic that you will use to enforce permissions + * on the server, then isAuthorized is the method that you want to use. + * + * Typically, assertAuthorized should be used to enforce permissions on the + * server. + * + * @param key key maps to + * <AccessControlPolicy><AccessControlRules> + * <AccessControlRule name="key" + * @param runtimeParameter runtimeParameter can contain anything that + * the AccessControlRule needs from the runtime system. + * @return Returns true if and only if the AccessControlRule specified + * by key exists and returned true. + * Otherwise returns false + */ + boolean isAuthorized(Object key, Object runtimeParameter); + + /** + * assertAuthorized executes the AccessControlRule + * that is identified by key and listed in the + * resources/ESAPI-AccessControlPolicy.xml file. It does + * nothing if the AccessControlRule decides that the operation + * should be allowed. Otherwise, it throws an + * org.owasp.esapi.errors.AccessControlException. Any exception + * thrown by the AccessControlRule will also result in an + * AccesControlException. If key does not map to + * an AccessControlRule, then an AccessControlException + * is thrown. + * + * Developers should call {@code assertAuthorized} to enforce privileged access to + * the system. It should be used to answer the question: "Should execution + * continue." Ideally, the call to assertAuthorized should + * be integrated into the application framework so that it is called + * automatically. + * + * @param key key maps to + * <AccessControlPolicy><AccessControlRules> + * <AccessControlRule name="key" + * @param runtimeParameter runtimeParameter can contain anything that + * the AccessControlRule needs from the runtime system. + */ + void assertAuthorized(Object key, Object runtimeParameter) + throws AccessControlException; - + - - /*** Below this line has been deprecated as of ESAPI 1.6 ***/ - - - - + + /*** Below this line has been deprecated as of ESAPI 1.6 ***/ + + + + /** * Checks if the current user is authorized to access the referenced URL. Generally, this method should be invoked in the * application's controller or a filter as follows: @@ -140,10 +140,10 @@ void assertAuthorized(Object key, Object runtimeParameter) * exception would be logged. * * @param url - * the URL as returned by request.getRequestURI().toString() + * the URL as returned by request.getRequestURI().toString() * * @return - * true, if is authorized for URL + * true, if is authorized for URL */ @Deprecated boolean isAuthorizedForURL(String url); @@ -155,10 +155,10 @@ void assertAuthorized(Object key, Object runtimeParameter) * AccessControlException is not thrown, this method should return true. * * @param functionName - * the name of the function + * the name of the function * * @return - * true, if is authorized for function + * true, if is authorized for function */ @Deprecated boolean isAuthorizedForFunction(String functionName); @@ -175,10 +175,10 @@ void assertAuthorized(Object key, Object runtimeParameter) * (e.g., Read, Write, etc.), or the name of the function the data is being passed to. * * @param data - * The actual object or object identifier being accessed or a reference to the object being accessed. + * The actual object or object identifier being accessed or a reference to the object being accessed. * * @return - * true, if is authorized for the data + * true, if is authorized for the data */ @Deprecated boolean isAuthorizedForData(String action, Object data); @@ -190,10 +190,10 @@ void assertAuthorized(Object key, Object runtimeParameter) * is not thrown, this method should return true. * * @param filepath - * the path of the file to be checked, including filename + * the path of the file to be checked, including filename * * @return - * true, if is authorized for the file + * true, if is authorized for the file */ @Deprecated boolean isAuthorizedForFile(String filepath); @@ -206,10 +206,10 @@ void assertAuthorized(Object key, Object runtimeParameter) * AccessControlException is not thrown, this method should return true. * * @param serviceName - * the service name + * the service name * * @return - * true, if is authorized for the service + * true, if is authorized for the service */ @Deprecated boolean isAuthorizedForService(String serviceName); @@ -229,16 +229,16 @@ void assertAuthorized(Object key, Object runtimeParameter) *
  • Use available information to make an access control decision
  • *
      *
    1. Ideally, this policy would be data driven
    2. - *
    3. You can use the current User, roles, data type, data name, time of day, etc.
    4. - *
    5. Access control decisions must deny by default
    6. + *
    7. You can use the current User, roles, data type, data name, time of day, etc.
    8. + *
    9. Access control decisions must deny by default
    10. *
    *
  • If access is not permitted, throw an AccessControlException with details
  • * * @param url - * the URL as returned by request.getRequestURI().toString() + * the URL as returned by request.getRequestURI().toString() * * @throws AccessControlException - * if access is not permitted + * if access is not permitted */ @Deprecated void assertAuthorizedForURL(String url) throws AccessControlException; @@ -257,17 +257,17 @@ void assertAuthorized(Object key, Object runtimeParameter) *
  • Use available information to make an access control decision
  • *
      *
    1. Ideally, this policy would be data driven
    2. - *
    3. You can use the current User, roles, data type, data name, time of day, etc.
    4. - *
    5. Access control decisions must deny by default
    6. + *
    7. You can use the current User, roles, data type, data name, time of day, etc.
    8. + *
    9. Access control decisions must deny by default
    10. *
    *
  • If access is not permitted, throw an AccessControlException with details
  • * * * @param functionName - * the function name + * the function name * * @throws AccessControlException - * if access is not permitted + * if access is not permitted */ @Deprecated void assertAuthorizedForFunction(String functionName) throws AccessControlException; @@ -283,8 +283,8 @@ void assertAuthorized(Object key, Object runtimeParameter) *
  • Use available information to make an access control decision
  • *
      *
    1. Ideally, this policy would be data driven
    2. - *
    3. You can use the current User, roles, data type, data name, time of day, etc.
    4. - *
    5. Access control decisions must deny by default
    6. + *
    7. You can use the current User, roles, data type, data name, time of day, etc.
    8. + *
    9. Access control decisions must deny by default
    10. *
    *
  • If access is not permitted, throw an AccessControlException with details
  • * @@ -294,10 +294,10 @@ void assertAuthorized(Object key, Object runtimeParameter) * (e.g., Read, Write, etc.), or the name of the function the data is being passed to. * * @param data - * The actual object or object identifier being accessed or a reference to the object being accessed. + * The actual object or object identifier being accessed or a reference to the object being accessed. * * @throws AccessControlException - * if access is not permitted + * if access is not permitted */ @Deprecated void assertAuthorizedForData(String action, Object data) throws AccessControlException; @@ -315,14 +315,14 @@ void assertAuthorized(Object key, Object runtimeParameter) *
  • Use available information to make an access control decision
  • *
      *
    1. Ideally, this policy would be data driven
    2. - *
    3. You can use the current User, roles, data type, data name, time of day, etc.
    4. - *
    5. Access control decisions must deny by default
    6. + *
    7. You can use the current User, roles, data type, data name, time of day, etc.
    8. + *
    9. Access control decisions must deny by default
    10. *
    *
  • If access is not permitted, throw an AccessControlException with details
  • * * * @param filepath - * Path to the file to be checked + * Path to the file to be checked * @throws AccessControlException if access is denied */ @Deprecated @@ -341,18 +341,18 @@ void assertAuthorized(Object key, Object runtimeParameter) *
  • Use available information to make an access control decision
  • *
      *
    1. Ideally, this policy would be data driven
    2. - *
    3. You can use the current User, roles, data type, data name, time of day, etc.
    4. - *
    5. Access control decisions must deny by default
    6. + *
    7. You can use the current User, roles, data type, data name, time of day, etc.
    8. + *
    9. Access control decisions must deny by default
    10. *
    *
  • If access is not permitted, throw an AccessControlException with details
  • * * * @param serviceName - * the service name + * the service name * * @throws AccessControlException - * if access is not permitted - */ + * if access is not permitted + */ @Deprecated void assertAuthorizedForService(String serviceName) throws AccessControlException; diff --git a/src/main/java/org/owasp/esapi/AccessReferenceMap.java b/src/main/java/org/owasp/esapi/AccessReferenceMap.java index 4fd74e01e..f9e8cdc83 100644 --- a/src/main/java/org/owasp/esapi/AccessReferenceMap.java +++ b/src/main/java/org/owasp/esapi/AccessReferenceMap.java @@ -63,34 +63,34 @@ */ public interface AccessReferenceMap extends Serializable { - /** - * Get an iterator through the direct object references. No guarantee is made as - * to the order of items returned. - * - * @return the iterator - */ - Iterator iterator(); + /** + * Get an iterator through the direct object references. No guarantee is made as + * to the order of items returned. + * + * @return the iterator + */ + Iterator iterator(); - /** - * Get a safe indirect reference to use in place of a potentially sensitive - * direct object reference. Developers should use this call when building - * URL's, form fields, hidden fields, etc... to help protect their private - * implementation information. - * - * @param directReference - * the direct reference - * - * @return - * the indirect reference - */ - K getIndirectReference(T directReference); + /** + * Get a safe indirect reference to use in place of a potentially sensitive + * direct object reference. Developers should use this call when building + * URL's, form fields, hidden fields, etc... to help protect their private + * implementation information. + * + * @param directReference + * the direct reference + * + * @return + * the indirect reference + */ + K getIndirectReference(T directReference); - /** - * Get the original direct object reference from an indirect reference. - * Developers should use this when they get an indirect reference from a - * request to translate it back into the real direct reference. If an - * invalid indirect reference is requested, then an AccessControlException is - * thrown. + /** + * Get the original direct object reference from an indirect reference. + * Developers should use this when they get an indirect reference from a + * request to translate it back into the real direct reference. If an + * invalid indirect reference is requested, then an AccessControlException is + * thrown. * * If a type is implied the requested object will be cast to that type, if the * object is not of the requested type, a AccessControlException will be thrown to @@ -122,55 +122,55 @@ public interface AccessReferenceMap extends Serializable { * // ... * } * - * - * @param indirectReference - * the indirect reference - * - * @return - * the direct reference - * - * @throws AccessControlException - * if no direct reference exists for the specified indirect reference + * + * @param indirectReference + * the indirect reference + * + * @return + * the direct reference + * + * @throws AccessControlException + * if no direct reference exists for the specified indirect reference * @throws ClassCastException * if the implied type is not the same as the referenced object type - */ - T getDirectReference(K indirectReference) throws AccessControlException; + */ + T getDirectReference(K indirectReference) throws AccessControlException; - /** - * Adds a direct reference to the AccessReferenceMap, then generates and returns - * an associated indirect reference. - * - * @param direct - * the direct reference - * - * @return - * the corresponding indirect reference - */ - K addDirectReference(T direct); - - /** - * Removes a direct reference and its associated indirect reference from the AccessReferenceMap. - * - * @param direct - * the direct reference to remove - * - * @return - * the corresponding indirect reference - * - * @throws AccessControlException + /** + * Adds a direct reference to the AccessReferenceMap, then generates and returns + * an associated indirect reference. + * + * @param direct + * the direct reference + * + * @return + * the corresponding indirect reference + */ + K addDirectReference(T direct); + + /** + * Removes a direct reference and its associated indirect reference from the AccessReferenceMap. + * + * @param direct + * the direct reference to remove + * + * @return + * the corresponding indirect reference + * + * @throws AccessControlException * if the reference does not exist. - */ - K removeDirectReference(T direct) throws AccessControlException; + */ + K removeDirectReference(T direct) throws AccessControlException; - /** - * Updates the access reference map with a new set of direct references, maintaining - * any existing indirect references associated with items that are in the new list. - * New indirect references could be generated every time, but that - * might mess up anything that previously used an indirect reference, such - * as a URL parameter. - * - * @param directReferences - * a Set of direct references to add - */ - void update(Set directReferences); + /** + * Updates the access reference map with a new set of direct references, maintaining + * any existing indirect references associated with items that are in the new list. + * New indirect references could be generated every time, but that + * might mess up anything that previously used an indirect reference, such + * as a URL parameter. + * + * @param directReferences + * a Set of direct references to add + */ + void update(Set directReferences); } diff --git a/src/main/java/org/owasp/esapi/Authenticator.java b/src/main/java/org/owasp/esapi/Authenticator.java index 57c090a46..bbc07ab90 100644 --- a/src/main/java/org/owasp/esapi/Authenticator.java +++ b/src/main/java/org/owasp/esapi/Authenticator.java @@ -59,92 +59,92 @@ */ public interface Authenticator { - /** - * Clears the current User. This allows the thread to be reused safely. + /** + * Clears the current User. This allows the thread to be reused safely. * * This clears all threadlocal variables from the thread. This should ONLY be called after * all possible ESAPI operations have concluded. If you clear too early, many calls will * fail, including logging, which requires the user identity. - */ - void clearCurrent(); + */ + void clearCurrent(); - /** - * Calls login with the *current* request and response. - * @return Authenticated {@code User} if login is successful. - * @see HTTPUtilities#setCurrentHTTP(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) - */ - User login() throws AuthenticationException; - - /** - * This method should be called for every HTTP request, to login the current user either from the session of HTTP + /** + * Calls login with the *current* request and response. + * @return Authenticated {@code User} if login is successful. + * @see HTTPUtilities#setCurrentHTTP(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + User login() throws AuthenticationException; + + /** + * This method should be called for every HTTP request, to login the current user either from the session of HTTP * request. This method will set the current user so that getCurrentUser() will work properly. - * - * Authenticates the user's credentials from the HttpServletRequest if - * necessary, creates a session if necessary, and sets the user as the - * current user. - * - * Specification: The implementation should do the following: - * 1) Check if the User is already stored in the session - * a. If so, check that session absolute and inactivity timeout have not expired - * b. Step 2 may not be required if 1a has been satisfied - * 2) Verify User credentials - * a. It is recommended that you use - * loginWithUsernameAndPassword(HttpServletRequest, HttpServletResponse) to verify credentials - * 3) Set the last host of the User (ex. user.setLastHostAddress(address) ) - * 4) Verify that the request is secure (ex. over SSL) - * 5) Verify the User account is allowed to be logged in - * a. Verify the User is not disabled, expired or locked - * 6) Assign User to session variable - * - * @param request - * the current HTTP request - * @param response - * the HTTP response - * - * @return - * the User - * - * @throws AuthenticationException - * if the credentials are not verified, or if the account is disabled, locked, expired, or timed out - */ - User login(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException; + * + * Authenticates the user's credentials from the HttpServletRequest if + * necessary, creates a session if necessary, and sets the user as the + * current user. + * + * Specification: The implementation should do the following: + * 1) Check if the User is already stored in the session + * a. If so, check that session absolute and inactivity timeout have not expired + * b. Step 2 may not be required if 1a has been satisfied + * 2) Verify User credentials + * a. It is recommended that you use + * loginWithUsernameAndPassword(HttpServletRequest, HttpServletResponse) to verify credentials + * 3) Set the last host of the User (ex. user.setLastHostAddress(address) ) + * 4) Verify that the request is secure (ex. over SSL) + * 5) Verify the User account is allowed to be logged in + * a. Verify the User is not disabled, expired or locked + * 6) Assign User to session variable + * + * @param request + * the current HTTP request + * @param response + * the HTTP response + * + * @return + * the User + * + * @throws AuthenticationException + * if the credentials are not verified, or if the account is disabled, locked, expired, or timed out + */ + User login(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException; - /** - * Verify that the supplied password matches the password for this user. Password should - * be stored as a hash. By default, this method verifies password hashes created via the + /** + * Verify that the supplied password matches the password for this user. Password should + * be stored as a hash. By default, this method verifies password hashes created via the * {@code hashPassword(password, accountName)} method in this class, however see WARNING * the {@code hashPassword} method. *

    - * This method is typically used for "reauthentication" for the most sensitive functions, such - * as transactions, changing email address, and changing other account information. - * - * @param user - * the user who requires verification - * @param password - * the hashed user-supplied password - * - * @return - * true, if the password is correct for the specified user + * This method is typically used for "reauthentication" for the most sensitive functions, such + * as transactions, changing email address, and changing other account information. + * + * @param user + * the user who requires verification + * @param password + * the hashed user-supplied password + * + * @return + * true, if the password is correct for the specified user * * @see #hashPassword(String password, String accountName) - */ - boolean verifyPassword(User user, String password); - - /** - * Logs out the current user. - * - * This is usually done by calling User.logout on the current User. - */ + */ + boolean verifyPassword(User user, String password); + + /** + * Logs out the current user. + * + * This is usually done by calling User.logout on the current User. + */ void logout(); - /** - * Creates a new User with the information provided. Implementations should check - * accountName and password for proper format and strength against brute force - * attacks ( verifyAccountNameStrength(String), verifyPasswordStrength(String, String) ). - * - * Two copies of the new password are required to encourage user interface designers to - * include a "re-type password" field in their forms. Implementations should verify that - * both are the same. + /** + * Creates a new User with the information provided. Implementations should check + * accountName and password for proper format and strength against brute force + * attacks ( verifyAccountNameStrength(String), verifyPasswordStrength(String, String) ). + * + * Two copies of the new password are required to encourage user interface designers to + * include a "re-type password" field in their forms. Implementations should verify that + * both are the same. *

    * WARNING: The implementation of this method as defined in the * default reference implementation class, {@code FileBasedAuthenticator}, @@ -152,122 +152,122 @@ public interface Authenticator { * to replace the default reference implementation class with your own custom * implementation that uses a stronger password hashing algorithm. * See class comments in * {@code FileBasedAuthenticator} for further details. - * - * @param accountName - * the account name of the new user - * @param password1 - * the password of the new user - * @param password2 - * the password of the new user. This field is to encourage user interface designers to include two password fields in their forms. - * - * @return - * the User that has been created - * - * @throws AuthenticationException - * if user creation fails due to any of the qualifications listed in this method's description - */ - User createUser(String accountName, String password1, String password2) throws AuthenticationException; + * + * @param accountName + * the account name of the new user + * @param password1 + * the password of the new user + * @param password2 + * the password of the new user. This field is to encourage user interface designers to include two password fields in their forms. + * + * @return + * the User that has been created + * + * @throws AuthenticationException + * if user creation fails due to any of the qualifications listed in this method's description + */ + User createUser(String accountName, String password1, String password2) throws AuthenticationException; - /** - * Generate a strong password. Implementations should use a large character set that does not - * include confusing characters, such as i I 1 l 0 o and O. There are many algorithms to - * generate strong memorable passwords that have been studied in the past. - * - * @return - * a password with strong password strength - */ - String generateStrongPassword(); + /** + * Generate a strong password. Implementations should use a large character set that does not + * include confusing characters, such as i I 1 l 0 o and O. There are many algorithms to + * generate strong memorable passwords that have been studied in the past. + * + * @return + * a password with strong password strength + */ + String generateStrongPassword(); - /** - * Generate strong password that takes into account the user's information and old password. Implementations - * should verify that the new password does not include information such as the username, fragments of the - * old password, and other information that could be used to weaken the strength of the password. - * - * @param user - * the user whose information to use when generating password - * @param oldPassword - * the old password to use when verifying strength of new password. The new password may be checked for fragments of oldPassword. - * - * @return - * a password with strong password strength - */ - String generateStrongPassword(User user, String oldPassword); + /** + * Generate strong password that takes into account the user's information and old password. Implementations + * should verify that the new password does not include information such as the username, fragments of the + * old password, and other information that could be used to weaken the strength of the password. + * + * @param user + * the user whose information to use when generating password + * @param oldPassword + * the old password to use when verifying strength of new password. The new password may be checked for fragments of oldPassword. + * + * @return + * a password with strong password strength + */ + String generateStrongPassword(User user, String oldPassword); - /** - * Changes the password for the specified user. This requires the current password, as well as - * the password to replace it with. The new password should be checked against old hashes to be sure the new password does not closely resemble or equal any recent passwords for that User. - * Password strength should also be verified. This new password must be repeated to ensure that the user has typed it in correctly. - * - * @param user - * the user to change the password for - * @param currentPassword - * the current password for the specified user - * @param newPassword - * the new password to use - * @param newPassword2 - * a verification copy of the new password - * - * @throws AuthenticationException - * if any errors occur - */ - void changePassword(User user, String currentPassword, String newPassword, String newPassword2) throws AuthenticationException; - - /** - * Returns the User matching the provided accountId. If the accoundId is not found, an Anonymous - * User or null may be returned. - * - * @param accountId - * the account id - * - * @return - * the matching User object, or the Anonymous User if no match exists - */ - User getUser(long accountId); - - /** - * Returns the User matching the provided accountName. If the accoundId is not found, an Anonymous - * User or null may be returned. - * - * @param accountName - * the account name - * - * @return - * the matching User object, or the Anonymous User if no match exists - */ - User getUser(String accountName); + /** + * Changes the password for the specified user. This requires the current password, as well as + * the password to replace it with. The new password should be checked against old hashes to be sure the new password does not closely resemble or equal any recent passwords for that User. + * Password strength should also be verified. This new password must be repeated to ensure that the user has typed it in correctly. + * + * @param user + * the user to change the password for + * @param currentPassword + * the current password for the specified user + * @param newPassword + * the new password to use + * @param newPassword2 + * a verification copy of the new password + * + * @throws AuthenticationException + * if any errors occur + */ + void changePassword(User user, String currentPassword, String newPassword, String newPassword2) throws AuthenticationException; + + /** + * Returns the User matching the provided accountId. If the accoundId is not found, an Anonymous + * User or null may be returned. + * + * @param accountId + * the account id + * + * @return + * the matching User object, or the Anonymous User if no match exists + */ + User getUser(long accountId); + + /** + * Returns the User matching the provided accountName. If the accoundId is not found, an Anonymous + * User or null may be returned. + * + * @param accountName + * the account name + * + * @return + * the matching User object, or the Anonymous User if no match exists + */ + User getUser(String accountName); - /** - * Gets a collection containing all the existing user names. - * - * @return - * a set of all user names - */ - Set getUserNames(); + /** + * Gets a collection containing all the existing user names. + * + * @return + * a set of all user names + */ + Set getUserNames(); - /** - * Returns the currently logged in User. - * - * @return - * the matching User object, or the Anonymous User if no match - * exists - */ - User getCurrentUser(); + /** + * Returns the currently logged in User. + * + * @return + * the matching User object, or the Anonymous User if no match + * exists + */ + User getCurrentUser(); - /** - * Sets the currently logged in User. - * - * @param user - * the user to set as the current user - */ - void setCurrentUser(User user); + /** + * Sets the currently logged in User. + * + * @param user + * the user to set as the current user + */ + void setCurrentUser(User user); - /** - * Returns a string representation of the hashed password, using the - * accountName as the salt. The salt helps to prevent against "rainbow" - * table attacks where the attacker pre-calculates hashes for known strings. - * This method specifies the use of the user's account name as the "salt" - * value. The Encryptor.hash method can be used if a different salt is - * required. + /** + * Returns a string representation of the hashed password, using the + * accountName as the salt. The salt helps to prevent against "rainbow" + * table attacks where the attacker pre-calculates hashes for known strings. + * This method specifies the use of the user's account name as the "salt" + * value. The Encryptor.hash method can be used if a different salt is + * required. *

    * WARNING: The implementation of this method as defined in the * default reference implementation class, {@code FileBasedAuthenticator}, @@ -275,71 +275,71 @@ public interface Authenticator { * meant to be an example implementation and generally should be avoided * and replaced with your own implementation. See class comments in * {@code FileBasedAuthenticator} for further details. - * - * @param password - * the password to hash - * @param accountName - * the account name to use as the salt - * - * @return - * the hashed password + * + * @param password + * the password to hash + * @param accountName + * the account name to use as the salt + * + * @return + * the hashed password * @throws EncryptionException * * @see org.owasp.esapi.reference.FileBasedAuthenticator FileBasedAuthenticator, * the default reference implementation of this interface. - */ - String hashPassword(String password, String accountName) throws EncryptionException; + */ + String hashPassword(String password, String accountName) throws EncryptionException; - /** - * Removes the account of the specified accountName. - * - * @param accountName - * the account name to remove - * - * @throws AuthenticationException - * the authentication exception if user does not exist - */ - void removeUser(String accountName) throws AuthenticationException; + /** + * Removes the account of the specified accountName. + * + * @param accountName + * the account name to remove + * + * @throws AuthenticationException + * the authentication exception if user does not exist + */ + void removeUser(String accountName) throws AuthenticationException; - /** - * Ensures that the account name passes site-specific complexity requirements, like minimum length. - * - * @param accountName - * the account name - * - * @throws AuthenticationException - * if account name does not meet complexity requirements - */ - void verifyAccountNameStrength(String accountName) throws AuthenticationException; + /** + * Ensures that the account name passes site-specific complexity requirements, like minimum length. + * + * @param accountName + * the account name + * + * @throws AuthenticationException + * if account name does not meet complexity requirements + */ + void verifyAccountNameStrength(String accountName) throws AuthenticationException; - /** - * Ensures that the password meets site-specific complexity requirements, like length or number - * of character sets. This method takes the old password so that the algorithm can analyze the - * new password to see if it is too similar to the old password. Note that this has to be - * invoked when the user has entered the old password, as the list of old - * credentials stored by ESAPI is all hashed. - * Additionally, the user object is taken in order to verify the password and account name differ. - * - * @param oldPassword - * the old password - * @param newPassword - * the new password - * @param user - * the user - * - * @throws AuthenticationException - * if newPassword is too similar to oldPassword or if newPassword does not meet complexity requirements - */ - void verifyPasswordStrength(String oldPassword, String newPassword, User user) throws AuthenticationException; + /** + * Ensures that the password meets site-specific complexity requirements, like length or number + * of character sets. This method takes the old password so that the algorithm can analyze the + * new password to see if it is too similar to the old password. Note that this has to be + * invoked when the user has entered the old password, as the list of old + * credentials stored by ESAPI is all hashed. + * Additionally, the user object is taken in order to verify the password and account name differ. + * + * @param oldPassword + * the old password + * @param newPassword + * the new password + * @param user + * the user + * + * @throws AuthenticationException + * if newPassword is too similar to oldPassword or if newPassword does not meet complexity requirements + */ + void verifyPasswordStrength(String oldPassword, String newPassword, User user) throws AuthenticationException; - /** - * Determine if the account exists. - * - * @param accountName - * the account name - * - * @return true, if the account exists - */ - boolean exists(String accountName); + /** + * Determine if the account exists. + * + * @param accountName + * the account name + * + * @return true, if the account exists + */ + boolean exists(String accountName); } diff --git a/src/main/java/org/owasp/esapi/ESAPI.java b/src/main/java/org/owasp/esapi/ESAPI.java index e11239c75..283156edf 100644 --- a/src/main/java/org/owasp/esapi/ESAPI.java +++ b/src/main/java/org/owasp/esapi/ESAPI.java @@ -26,171 +26,171 @@ * Use the set methods to override the reference implementations with instances of any custom ESAPI implementations. */ public final class ESAPI { - private static String securityConfigurationImplName = System.getProperty("org.owasp.esapi.SecurityConfiguration", "org.owasp.esapi.reference.DefaultSecurityConfiguration"); - - /** - * prevent instantiation of this class - */ - private ESAPI() { - } - - /** - * Clears the current User, HttpRequest, and HttpResponse associated with the current thread. This method - * MUST be called as some containers do not properly clear threadlocal variables when the execution of - * a thread is complete. The suggested approach is to put this call in a finally block inside a filter. - *

    -		public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException {
    -			try {
    -				HttpServletRequest request = (HttpServletRequest) req;
    -				HttpServletResponse response = (HttpServletResponse) resp;
    -				ESAPI.httpUtilities().setCurrentHTTP(request, response);
    -				ESAPI.authenticator().login();
    -				chain.doFilter(request, response);
    -			} catch (Exception e) {
    -				logger.error( Logger.SECURITY_FAILURE, "Error in ESAPI security filter: " + e.getMessage(), e );
    -			} finally {
    -				// VERY IMPORTANT
    -				// clear out ThreadLocal variables
    -				ESAPI.clearCurrent();
    -			}
    -		}
    -	 * 
    - * The advantages of having identity everywhere are worth the risk here. - */ - public static void clearCurrent() { - authenticator().clearCurrent(); - httpUtilities().clearCurrent(); - } - - /** - * Get the current HTTP Servlet Request being processed. - * @return the current HTTP Servlet Request. - */ - public static HttpServletRequest currentRequest() { - return httpUtilities().getCurrentRequest(); - } - - /** - * Get the current HTTP Servlet Response being generated. - * @return the current HTTP Servlet Response. - */ - public static HttpServletResponse currentResponse() { - return httpUtilities().getCurrentResponse(); - } - - /** - * @return the current ESAPI AccessController object being used to maintain the access control rules for this application. - */ - public static AccessController accessController() { + private static String securityConfigurationImplName = System.getProperty("org.owasp.esapi.SecurityConfiguration", "org.owasp.esapi.reference.DefaultSecurityConfiguration"); + + /** + * prevent instantiation of this class + */ + private ESAPI() { + } + + /** + * Clears the current User, HttpRequest, and HttpResponse associated with the current thread. This method + * MUST be called as some containers do not properly clear threadlocal variables when the execution of + * a thread is complete. The suggested approach is to put this call in a finally block inside a filter. + *
    +        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException {
    +            try {
    +                HttpServletRequest request = (HttpServletRequest) req;
    +                HttpServletResponse response = (HttpServletResponse) resp;
    +                ESAPI.httpUtilities().setCurrentHTTP(request, response);
    +                ESAPI.authenticator().login();
    +                chain.doFilter(request, response);
    +            } catch (Exception e) {
    +                logger.error( Logger.SECURITY_FAILURE, "Error in ESAPI security filter: " + e.getMessage(), e );
    +            } finally {
    +                // VERY IMPORTANT
    +                // clear out ThreadLocal variables
    +                ESAPI.clearCurrent();
    +            }
    +        }
    +     * 
    + * The advantages of having identity everywhere are worth the risk here. + */ + public static void clearCurrent() { + authenticator().clearCurrent(); + httpUtilities().clearCurrent(); + } + + /** + * Get the current HTTP Servlet Request being processed. + * @return the current HTTP Servlet Request. + */ + public static HttpServletRequest currentRequest() { + return httpUtilities().getCurrentRequest(); + } + + /** + * Get the current HTTP Servlet Response being generated. + * @return the current HTTP Servlet Response. + */ + public static HttpServletResponse currentResponse() { + return httpUtilities().getCurrentResponse(); + } + + /** + * @return the current ESAPI AccessController object being used to maintain the access control rules for this application. + */ + public static AccessController accessController() { return ObjFactory.make( securityConfiguration().getAccessControlImplementation(), "AccessController" ); - } + } - /** - * @return the current ESAPI Authenticator object being used to authenticate users for this application. - */ - public static Authenticator authenticator() { + /** + * @return the current ESAPI Authenticator object being used to authenticate users for this application. + */ + public static Authenticator authenticator() { return ObjFactory.make( securityConfiguration().getAuthenticationImplementation(), "Authenticator" ); - } + } - /** + /** * The ESAPI Encoder is primarilly used to provide output encoding to * prevent Cross-Site Scripting (XSS). - * @return the current ESAPI Encoder object being used to encode and decode data for this application. - */ - public static Encoder encoder() { + * @return the current ESAPI Encoder object being used to encode and decode data for this application. + */ + public static Encoder encoder() { return ObjFactory.make( securityConfiguration().getEncoderImplementation(), "Encoder" ); - } + } - /** - * @return the current ESAPI Encryptor object being used to encrypt and decrypt data for this application. - */ - public static Encryptor encryptor() { + /** + * @return the current ESAPI Encryptor object being used to encrypt and decrypt data for this application. + */ + public static Encryptor encryptor() { return ObjFactory.make( securityConfiguration().getEncryptionImplementation(), "Encryptor" ); - } + } - /** - * @return the current ESAPI Executor object being used to safely execute OS commands for this application. - */ - public static Executor executor() { + /** + * @return the current ESAPI Executor object being used to safely execute OS commands for this application. + */ + public static Executor executor() { return ObjFactory.make( securityConfiguration().getExecutorImplementation(), "Executor" ); - } + } - /** - * @return the current ESAPI HTTPUtilities object being used to safely access HTTP requests and responses - * for this application. - */ - public static HTTPUtilities httpUtilities() { + /** + * @return the current ESAPI HTTPUtilities object being used to safely access HTTP requests and responses + * for this application. + */ + public static HTTPUtilities httpUtilities() { return ObjFactory.make( securityConfiguration().getHTTPUtilitiesImplementation(), "HTTPUtilities" ); - } + } - /** - * @return the current ESAPI IntrusionDetector being used to monitor for intrusions in this application. - */ - public static IntrusionDetector intrusionDetector() { + /** + * @return the current ESAPI IntrusionDetector being used to monitor for intrusions in this application. + */ + public static IntrusionDetector intrusionDetector() { return ObjFactory.make( securityConfiguration().getIntrusionDetectionImplementation(), "IntrusionDetector" ); - } - - /** - * Get the current LogFactory being used by ESAPI. If there isn't one yet, it will create one, and then - * return this same LogFactory from then on. - * @return The current LogFactory being used by ESAPI. - */ - private static LogFactory logFactory() { + } + + /** + * Get the current LogFactory being used by ESAPI. If there isn't one yet, it will create one, and then + * return this same LogFactory from then on. + * @return The current LogFactory being used by ESAPI. + */ + private static LogFactory logFactory() { return ObjFactory.make( securityConfiguration().getLogImplementation(), "LogFactory" ); - } - - /** - * @param clazz The class to associate the logger with. - * @return The current Logger associated with the specified class. - */ - public static Logger getLogger(Class clazz) { - return logFactory().getLogger(clazz); - } - - /** - * @param moduleName The module to associate the logger with. - * @return The current Logger associated with the specified module. - */ - public static Logger getLogger(String moduleName) { - return logFactory().getLogger(moduleName); - } - - /** - * @return The default Logger. - */ - public static Logger log() { + } + + /** + * @param clazz The class to associate the logger with. + * @return The current Logger associated with the specified class. + */ + public static Logger getLogger(Class clazz) { + return logFactory().getLogger(clazz); + } + + /** + * @param moduleName The module to associate the logger with. + * @return The current Logger associated with the specified module. + */ + public static Logger getLogger(String moduleName) { + return logFactory().getLogger(moduleName); + } + + /** + * @return The default Logger. + */ + public static Logger log() { return logFactory().getLogger("DefaultLogger"); } - - /** - * @return the current ESAPI Randomizer being used to generate random numbers in this application. - */ - public static Randomizer randomizer() { + + /** + * @return the current ESAPI Randomizer being used to generate random numbers in this application. + */ + public static Randomizer randomizer() { return ObjFactory.make( securityConfiguration().getRandomizerImplementation(), "Randomizer" ); - } + } private static volatile SecurityConfiguration overrideConfig = null; - /** - * @return the current ESAPI SecurityConfiguration being used to manage the security configuration for - * ESAPI for this application. - */ - public static SecurityConfiguration securityConfiguration() { - // copy the volatile into a non-volatile to prevent TOCTTOU race condition - SecurityConfiguration override = overrideConfig; - if ( override != null ) { - return override; + /** + * @return the current ESAPI SecurityConfiguration being used to manage the security configuration for + * ESAPI for this application. + */ + public static SecurityConfiguration securityConfiguration() { + // copy the volatile into a non-volatile to prevent TOCTTOU race condition + SecurityConfiguration override = overrideConfig; + if ( override != null ) { + return override; } return ObjFactory.make( securityConfigurationImplName, "SecurityConfiguration" ); - } + } - /** - * @return the current ESAPI Validator being used to validate data in this application. - */ - public static Validator validator() { + /** + * @return the current ESAPI Validator being used to validate data in this application. + */ + public static Validator validator() { return ObjFactory.make( securityConfiguration().getValidationImplementation(), "Validator" ); - } + } // TODO: This should probably use the SecurityManager or some value within the current // securityConfiguration to determine if this method is allowed to be called. This could diff --git a/src/main/java/org/owasp/esapi/EncoderConstants.java b/src/main/java/org/owasp/esapi/EncoderConstants.java index 1498d5ea7..724b15ad4 100644 --- a/src/main/java/org/owasp/esapi/EncoderConstants.java +++ b/src/main/java/org/owasp/esapi/EncoderConstants.java @@ -11,107 +11,107 @@ * @see User */ public class EncoderConstants { - /** - * !$*-.=?@_ - */ - public final static char[] CHAR_PASSWORD_SPECIALS = { '!', '$', '*', '-', '.', '=', '?', '@', '_' }; - public final static Set PASSWORD_SPECIALS; - static { - PASSWORD_SPECIALS = CollectionsUtil.arrayToSet(CHAR_PASSWORD_SPECIALS); - } - - /** - * a-b - */ - public final static char[] CHAR_LOWERS = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; - public final static Set LOWERS; - static { - LOWERS = CollectionsUtil.arrayToSet(CHAR_PASSWORD_SPECIALS); - } - - /** - * A-Z - */ - public final static char[] CHAR_UPPERS = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; - public final static Set UPPERS; - static { - UPPERS = CollectionsUtil.arrayToSet(CHAR_UPPERS); - } - /** - * 0-9 - */ - public final static char[] CHAR_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; - public final static Set DIGITS; - static { - DIGITS = CollectionsUtil.arrayToSet(CHAR_DIGITS); - } - - /** - * !$*+-.=?@^_|~ - */ - public final static char[] CHAR_SPECIALS = { '!', '$', '*', '+', '-', '.', '=', '?', '@', '^', '_', '|', '~' }; - public final static Set SPECIALS; - static { - SPECIALS = CollectionsUtil.arrayToSet(CHAR_SPECIALS); - } - - /** - * CHAR_LOWERS union CHAR_UPPERS - */ - public final static char[] CHAR_LETTERS = StringUtilities.union(CHAR_LOWERS, CHAR_UPPERS); - public final static Set LETTERS; - static { - LETTERS = CollectionsUtil.arrayToSet(CHAR_LETTERS); - } - - /** - * CHAR_LETTERS union CHAR_DIGITS - */ - public final static char[] CHAR_ALPHANUMERICS = StringUtilities.union(CHAR_LETTERS, CHAR_DIGITS); - public final static Set ALPHANUMERICS; - static { - ALPHANUMERICS = CollectionsUtil.arrayToSet(CHAR_ALPHANUMERICS); - } - - /** - * Password character set, is alphanumerics (without l, i, I, o, O, and 0) - * selected specials like + (bad for URL encoding, | is like i and 1, - * etc...) - */ - public final static char[] CHAR_PASSWORD_LOWERS = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; - public final static Set PASSWORD_LOWERS; - static { - PASSWORD_LOWERS = CollectionsUtil.arrayToSet(CHAR_ALPHANUMERICS); - } - - /** - * - */ - public final static char[] CHAR_PASSWORD_UPPERS = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; - public final static Set PASSWORD_UPPERS; - static { - PASSWORD_UPPERS = CollectionsUtil.arrayToSet(CHAR_PASSWORD_UPPERS); - } - - /** - * 2-9 - */ - public final static char[] CHAR_PASSWORD_DIGITS = { '2', '3', '4', '5', '6', '7', '8', '9' }; - public final static Set PASSWORD_DIGITS; - static { - PASSWORD_DIGITS = CollectionsUtil.arrayToSet(CHAR_PASSWORD_DIGITS); - } - - /** - * CHAR_PASSWORD_LOWERS union CHAR_PASSWORD_UPPERS - */ - public final static char[] CHAR_PASSWORD_LETTERS = StringUtilities.union( CHAR_PASSWORD_LOWERS, CHAR_PASSWORD_UPPERS ); - public final static Set PASSWORD_LETTERS; - static { - PASSWORD_LETTERS = CollectionsUtil.arrayToSet(CHAR_PASSWORD_LETTERS); - } + /** + * !$*-.=?@_ + */ + public final static char[] CHAR_PASSWORD_SPECIALS = { '!', '$', '*', '-', '.', '=', '?', '@', '_' }; + public final static Set PASSWORD_SPECIALS; + static { + PASSWORD_SPECIALS = CollectionsUtil.arrayToSet(CHAR_PASSWORD_SPECIALS); + } + + /** + * a-b + */ + public final static char[] CHAR_LOWERS = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; + public final static Set LOWERS; + static { + LOWERS = CollectionsUtil.arrayToSet(CHAR_PASSWORD_SPECIALS); + } + + /** + * A-Z + */ + public final static char[] CHAR_UPPERS = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; + public final static Set UPPERS; + static { + UPPERS = CollectionsUtil.arrayToSet(CHAR_UPPERS); + } + /** + * 0-9 + */ + public final static char[] CHAR_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; + public final static Set DIGITS; + static { + DIGITS = CollectionsUtil.arrayToSet(CHAR_DIGITS); + } + + /** + * !$*+-.=?@^_|~ + */ + public final static char[] CHAR_SPECIALS = { '!', '$', '*', '+', '-', '.', '=', '?', '@', '^', '_', '|', '~' }; + public final static Set SPECIALS; + static { + SPECIALS = CollectionsUtil.arrayToSet(CHAR_SPECIALS); + } + + /** + * CHAR_LOWERS union CHAR_UPPERS + */ + public final static char[] CHAR_LETTERS = StringUtilities.union(CHAR_LOWERS, CHAR_UPPERS); + public final static Set LETTERS; + static { + LETTERS = CollectionsUtil.arrayToSet(CHAR_LETTERS); + } + + /** + * CHAR_LETTERS union CHAR_DIGITS + */ + public final static char[] CHAR_ALPHANUMERICS = StringUtilities.union(CHAR_LETTERS, CHAR_DIGITS); + public final static Set ALPHANUMERICS; + static { + ALPHANUMERICS = CollectionsUtil.arrayToSet(CHAR_ALPHANUMERICS); + } + + /** + * Password character set, is alphanumerics (without l, i, I, o, O, and 0) + * selected specials like + (bad for URL encoding, | is like i and 1, + * etc...) + */ + public final static char[] CHAR_PASSWORD_LOWERS = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; + public final static Set PASSWORD_LOWERS; + static { + PASSWORD_LOWERS = CollectionsUtil.arrayToSet(CHAR_ALPHANUMERICS); + } + + /** + * + */ + public final static char[] CHAR_PASSWORD_UPPERS = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; + public final static Set PASSWORD_UPPERS; + static { + PASSWORD_UPPERS = CollectionsUtil.arrayToSet(CHAR_PASSWORD_UPPERS); + } + + /** + * 2-9 + */ + public final static char[] CHAR_PASSWORD_DIGITS = { '2', '3', '4', '5', '6', '7', '8', '9' }; + public final static Set PASSWORD_DIGITS; + static { + PASSWORD_DIGITS = CollectionsUtil.arrayToSet(CHAR_PASSWORD_DIGITS); + } + + /** + * CHAR_PASSWORD_LOWERS union CHAR_PASSWORD_UPPERS + */ + public final static char[] CHAR_PASSWORD_LETTERS = StringUtilities.union( CHAR_PASSWORD_LOWERS, CHAR_PASSWORD_UPPERS ); + public final static Set PASSWORD_LETTERS; + static { + PASSWORD_LETTERS = CollectionsUtil.arrayToSet(CHAR_PASSWORD_LETTERS); + } - private EncoderConstants() { - // prevent instantiation - } + private EncoderConstants() { + // prevent instantiation + } } diff --git a/src/main/java/org/owasp/esapi/EncryptedProperties.java b/src/main/java/org/owasp/esapi/EncryptedProperties.java index 9e1a857ac..fbec7e2c1 100644 --- a/src/main/java/org/owasp/esapi/EncryptedProperties.java +++ b/src/main/java/org/owasp/esapi/EncryptedProperties.java @@ -38,75 +38,75 @@ */ public interface EncryptedProperties { - /** - * Gets the property value from the encrypted store, decrypts it, and - * returns the plaintext value to the caller. - * - * @param key - * the name of the property to get - * - * @return - * The decrypted property value. null if the key is not set. - * - * @throws EncryptionException - * if the property could not be decrypted - */ - String getProperty(String key) throws EncryptionException; + /** + * Gets the property value from the encrypted store, decrypts it, and + * returns the plaintext value to the caller. + * + * @param key + * the name of the property to get + * + * @return + * The decrypted property value. null if the key is not set. + * + * @throws EncryptionException + * if the property could not be decrypted + */ + String getProperty(String key) throws EncryptionException; - /** - * Encrypts the plaintext property value and stores the ciphertext value - * in the encrypted store. - * - * @param key - * the name of the property to set - * @param value - * the value of the property to set - * - * @return - * the previously encrypted property value for the specified key, or - * {@code null} if it did not have one. - * - * @throws EncryptionException - * if the property could not be encrypted - */ - String setProperty(String key, String value) throws EncryptionException; - - /** - * Returns a {@code Set} view of properties. The {@code Set} is backed by a - * {@code java.util.Hashtable}, so changes to the {@code Hashtable} are - * reflected in the {@code Set}, and vice-versa. The {@code Set} supports element - * removal (which removes the corresponding entry from the {@code Hashtable}, - * but not element addition. - * - * @return - * a set view of the properties contained in this map. - */ - Set keySet(); - - /** - * Reads a property list (key and element pairs) from the input stream. - * - * @param in - * the input stream that contains the properties file - * - * @throws IOException - * Signals that an I/O exception has occurred. - */ - void load(InputStream in) throws IOException; - - /** - * Writes this property list (key and element pairs) in this Properties table to - * the output stream in a format suitable for loading into a Properties table using the load method. - * - * @param out - * the output stream that contains the properties file - * @param comments - * a description of the property list (ex. "Encrypted Properties File"). - * - * @throws IOException - * Signals that an I/O exception has occurred. - */ - void store(OutputStream out, String comments) throws IOException; - - + /** + * Encrypts the plaintext property value and stores the ciphertext value + * in the encrypted store. + * + * @param key + * the name of the property to set + * @param value + * the value of the property to set + * + * @return + * the previously encrypted property value for the specified key, or + * {@code null} if it did not have one. + * + * @throws EncryptionException + * if the property could not be encrypted + */ + String setProperty(String key, String value) throws EncryptionException; + + /** + * Returns a {@code Set} view of properties. The {@code Set} is backed by a + * {@code java.util.Hashtable}, so changes to the {@code Hashtable} are + * reflected in the {@code Set}, and vice-versa. The {@code Set} supports element + * removal (which removes the corresponding entry from the {@code Hashtable}, + * but not element addition. + * + * @return + * a set view of the properties contained in this map. + */ + Set keySet(); + + /** + * Reads a property list (key and element pairs) from the input stream. + * + * @param in + * the input stream that contains the properties file + * + * @throws IOException + * Signals that an I/O exception has occurred. + */ + void load(InputStream in) throws IOException; + + /** + * Writes this property list (key and element pairs) in this Properties table to + * the output stream in a format suitable for loading into a Properties table using the load method. + * + * @param out + * the output stream that contains the properties file + * @param comments + * a description of the property list (ex. "Encrypted Properties File"). + * + * @throws IOException + * Signals that an I/O exception has occurred. + */ + void store(OutputStream out, String comments) throws IOException; + + } diff --git a/src/main/java/org/owasp/esapi/Encryptor.java b/src/main/java/org/owasp/esapi/Encryptor.java index 6c83fef60..64134849b 100644 --- a/src/main/java/org/owasp/esapi/Encryptor.java +++ b/src/main/java/org/owasp/esapi/Encryptor.java @@ -57,177 +57,177 @@ */ public interface Encryptor { - /** - * Returns a string representation of the hash of the provided plaintext and - * salt. The salt helps to protect against a rainbow table attack by mixing - * in some extra data with the plaintext. Some good choices for a salt might - * be an account name or some other string that is known to the application - * but not to an attacker. - * See - * this article for more information about hashing as it pertains to password schemes. - * - * @param plaintext - * the plaintext String to encrypt - * @param salt - * the salt to add to the plaintext String before hashing - * - * @return - * the encrypted hash of 'plaintext' stored as a String - * - * @throws EncryptionException - * if the specified hash algorithm could not be found or another problem exists with - * the hashing of 'plaintext' - */ - String hash(String plaintext, String salt) throws EncryptionException; + /** + * Returns a string representation of the hash of the provided plaintext and + * salt. The salt helps to protect against a rainbow table attack by mixing + * in some extra data with the plaintext. Some good choices for a salt might + * be an account name or some other string that is known to the application + * but not to an attacker. + * See + * this article for more information about hashing as it pertains to password schemes. + * + * @param plaintext + * the plaintext String to encrypt + * @param salt + * the salt to add to the plaintext String before hashing + * + * @return + * the encrypted hash of 'plaintext' stored as a String + * + * @throws EncryptionException + * if the specified hash algorithm could not be found or another problem exists with + * the hashing of 'plaintext' + */ + String hash(String plaintext, String salt) throws EncryptionException; - /** - * Returns a string representation of the hash of the provided plaintext and - * salt. The salt helps to protect against a rainbow table attack by mixing - * in some extra data with the plaintext. Some good choices for a salt might - * be an account name or some other string that is known to the application - * but not to an attacker. - * See - * this article for more information about hashing as it pertains to password schemes. - * - * @param plaintext - * the plaintext String to encrypt - * @param salt - * the salt to add to the plaintext String before hashing - * @param iterations - * the number of times to iterate the hash - * - * @return - * the encrypted hash of 'plaintext' stored as a String - * - * @throws EncryptionException - * if the specified hash algorithm could not be found or another problem exists with - * the hashing of 'plaintext' - */ - String hash(String plaintext, String salt, int iterations) throws EncryptionException; - - /** - * Encrypts the provided plaintext bytes using the cipher transformation - * specified by the property Encryptor.CipherTransformation - * and the master encryption key as specified by the property - * {@code Encryptor.MasterKey} as defined in the ESAPI.properties file. - *

    - * - * @param plaintext The {@code PlainText} to be encrypted. - * @return the {@code CipherText} object from which the raw ciphertext, the - * IV, the cipher transformation, and many other aspects about - * the encryption detail may be extracted. - * @throws EncryptionException Thrown if something should go wrong such as - * the JCE provider cannot be found, the cipher algorithm, - * cipher mode, or padding scheme not being supported, specifying - * an unsupported key size, specifying an IV of incorrect length, - * etc. - * @see #encrypt(SecretKey, PlainText) - * @since 2.0 - */ - CipherText encrypt(PlainText plaintext) throws EncryptionException; + /** + * Returns a string representation of the hash of the provided plaintext and + * salt. The salt helps to protect against a rainbow table attack by mixing + * in some extra data with the plaintext. Some good choices for a salt might + * be an account name or some other string that is known to the application + * but not to an attacker. + * See + * this article for more information about hashing as it pertains to password schemes. + * + * @param plaintext + * the plaintext String to encrypt + * @param salt + * the salt to add to the plaintext String before hashing + * @param iterations + * the number of times to iterate the hash + * + * @return + * the encrypted hash of 'plaintext' stored as a String + * + * @throws EncryptionException + * if the specified hash algorithm could not be found or another problem exists with + * the hashing of 'plaintext' + */ + String hash(String plaintext, String salt, int iterations) throws EncryptionException; + + /** + * Encrypts the provided plaintext bytes using the cipher transformation + * specified by the property Encryptor.CipherTransformation + * and the master encryption key as specified by the property + * {@code Encryptor.MasterKey} as defined in the ESAPI.properties file. + *

    + * + * @param plaintext The {@code PlainText} to be encrypted. + * @return the {@code CipherText} object from which the raw ciphertext, the + * IV, the cipher transformation, and many other aspects about + * the encryption detail may be extracted. + * @throws EncryptionException Thrown if something should go wrong such as + * the JCE provider cannot be found, the cipher algorithm, + * cipher mode, or padding scheme not being supported, specifying + * an unsupported key size, specifying an IV of incorrect length, + * etc. + * @see #encrypt(SecretKey, PlainText) + * @since 2.0 + */ + CipherText encrypt(PlainText plaintext) throws EncryptionException; - /** - * Encrypts the provided plaintext bytes using the cipher transformation - * specified by the property Encryptor.CipherTransformation - * as defined in the ESAPI.properties file and the - * specified secret key. - *

    - * This method is similar to {@link #encrypt(PlainText)} except that it - * permits a specific {@code SecretKey} to be used for encryption. - * - * @param key The {@code SecretKey} to use for encrypting the plaintext. - * @param plaintext The byte stream to be encrypted. Note if a Java - * {@code String} is to be encrypted, it should be converted - * using {@code "some string".getBytes("UTF-8")}. - * @return the {@code CipherText} object from which the raw ciphertext, the - * IV, the cipher transformation, and many other aspects about - * the encryption detail may be extracted. - * @throws EncryptionException Thrown if something should go wrong such as - * the JCE provider cannot be found, the cipher algorithm, - * cipher mode, or padding scheme not being supported, specifying - * an unsupported key size, specifying an IV of incorrect length, - * etc. - * @see #encrypt(PlainText) - * @since 2.0 - */ - CipherText encrypt(SecretKey key, PlainText plaintext) - throws EncryptionException; + /** + * Encrypts the provided plaintext bytes using the cipher transformation + * specified by the property Encryptor.CipherTransformation + * as defined in the ESAPI.properties file and the + * specified secret key. + *

    + * This method is similar to {@link #encrypt(PlainText)} except that it + * permits a specific {@code SecretKey} to be used for encryption. + * + * @param key The {@code SecretKey} to use for encrypting the plaintext. + * @param plaintext The byte stream to be encrypted. Note if a Java + * {@code String} is to be encrypted, it should be converted + * using {@code "some string".getBytes("UTF-8")}. + * @return the {@code CipherText} object from which the raw ciphertext, the + * IV, the cipher transformation, and many other aspects about + * the encryption detail may be extracted. + * @throws EncryptionException Thrown if something should go wrong such as + * the JCE provider cannot be found, the cipher algorithm, + * cipher mode, or padding scheme not being supported, specifying + * an unsupported key size, specifying an IV of incorrect length, + * etc. + * @see #encrypt(PlainText) + * @since 2.0 + */ + CipherText encrypt(SecretKey key, PlainText plaintext) + throws EncryptionException; - /** - * Decrypts the provided {@link CipherText} using the information from it - * and the master encryption key as specified by the property - * {@code Encryptor.MasterKey} as defined in the {@code ESAPI.properties} - * file. - *

    - * @param ciphertext The {@code CipherText} object to be decrypted. - * @return The {@code PlainText} object resulting from decrypting the specified - * ciphertext. Note that it it is desired to convert the returned - * plaintext byte array to a Java String is should be done using - * {@code new String(byte[], "UTF-8");} rather than simply using - * {@code new String(byte[]);} which uses native encoding and may - * not be portable across hardware and/or OS platforms. - * @throws EncryptionException Thrown if something should go wrong such as - * the JCE provider cannot be found, the cipher algorithm, - * cipher mode, or padding scheme not being supported, specifying - * an unsupported key size, or incorrect encryption key was - * specified or a {@code PaddingException} occurs. - * @see #decrypt(SecretKey, CipherText) - */ - PlainText decrypt(CipherText ciphertext) throws EncryptionException; - - /** - * Decrypts the provided {@link CipherText} using the information from it - * and the specified secret key. - *

    - * This decrypt method is similar to {@link #decrypt(CipherText)} except that - * it allows decrypting with a secret key other than the master secret key. - *

    - * @param key The {@code SecretKey} to use for encrypting the plaintext. - * @param ciphertext The {@code CipherText} object to be decrypted. - * @return The {@code PlainText} object resulting from decrypting the specified - * ciphertext. Note that it it is desired to convert the returned - * plaintext byte array to a Java String is should be done using - * {@code new String(byte[], "UTF-8");} rather than simply using - * {@code new String(byte[]);} which uses native encoding and may - * not be portable across hardware and/or OS platforms. - * @throws EncryptionException Thrown if something should go wrong such as - * the JCE provider cannot be found, the cipher algorithm, - * cipher mode, or padding scheme not being supported, specifying - * an unsupported key size, or incorrect encryption key was - * specified or a {@code PaddingException} occurs. - * @see #decrypt(CipherText) - */ - PlainText decrypt(SecretKey key, CipherText ciphertext) throws EncryptionException; - - /** - * Create a digital signature for the provided data and return it in a - * string. - *

    - * Limitations: A new public/private key pair used for ESAPI 2.0 digital - * signatures with this method and {@link #verifySignature(String, String)} - * are dynamically created when the default reference implementation class, - * {@link org.owasp.esapi.reference.crypto.JavaEncryptor} is first created. - * Because this key pair is not persisted nor is the public key shared, - * this method and the corresponding {@link #verifySignature(String, String)} - * can not be used with expected results across JVM instances. This limitation - * will be addressed in ESAPI 2.1. - *

    - * - * @param data - * the data to sign - * - * @return - * the digital signature stored as a String - * - * @throws EncryptionException - * if the specified signature algorithm cannot be found - */ - String sign(String data) throws EncryptionException; + /** + * Decrypts the provided {@link CipherText} using the information from it + * and the master encryption key as specified by the property + * {@code Encryptor.MasterKey} as defined in the {@code ESAPI.properties} + * file. + *

    + * @param ciphertext The {@code CipherText} object to be decrypted. + * @return The {@code PlainText} object resulting from decrypting the specified + * ciphertext. Note that it it is desired to convert the returned + * plaintext byte array to a Java String is should be done using + * {@code new String(byte[], "UTF-8");} rather than simply using + * {@code new String(byte[]);} which uses native encoding and may + * not be portable across hardware and/or OS platforms. + * @throws EncryptionException Thrown if something should go wrong such as + * the JCE provider cannot be found, the cipher algorithm, + * cipher mode, or padding scheme not being supported, specifying + * an unsupported key size, or incorrect encryption key was + * specified or a {@code PaddingException} occurs. + * @see #decrypt(SecretKey, CipherText) + */ + PlainText decrypt(CipherText ciphertext) throws EncryptionException; + + /** + * Decrypts the provided {@link CipherText} using the information from it + * and the specified secret key. + *

    + * This decrypt method is similar to {@link #decrypt(CipherText)} except that + * it allows decrypting with a secret key other than the master secret key. + *

    + * @param key The {@code SecretKey} to use for encrypting the plaintext. + * @param ciphertext The {@code CipherText} object to be decrypted. + * @return The {@code PlainText} object resulting from decrypting the specified + * ciphertext. Note that it it is desired to convert the returned + * plaintext byte array to a Java String is should be done using + * {@code new String(byte[], "UTF-8");} rather than simply using + * {@code new String(byte[]);} which uses native encoding and may + * not be portable across hardware and/or OS platforms. + * @throws EncryptionException Thrown if something should go wrong such as + * the JCE provider cannot be found, the cipher algorithm, + * cipher mode, or padding scheme not being supported, specifying + * an unsupported key size, or incorrect encryption key was + * specified or a {@code PaddingException} occurs. + * @see #decrypt(CipherText) + */ + PlainText decrypt(SecretKey key, CipherText ciphertext) throws EncryptionException; + + /** + * Create a digital signature for the provided data and return it in a + * string. + *

    + * Limitations: A new public/private key pair used for ESAPI 2.0 digital + * signatures with this method and {@link #verifySignature(String, String)} + * are dynamically created when the default reference implementation class, + * {@link org.owasp.esapi.reference.crypto.JavaEncryptor} is first created. + * Because this key pair is not persisted nor is the public key shared, + * this method and the corresponding {@link #verifySignature(String, String)} + * can not be used with expected results across JVM instances. This limitation + * will be addressed in ESAPI 2.1. + *

    + * + * @param data + * the data to sign + * + * @return + * the digital signature stored as a String + * + * @throws EncryptionException + * if the specified signature algorithm cannot be found + */ + String sign(String data) throws EncryptionException; - /** - * Verifies a digital signature (created with the sign method) and returns - * the boolean result. + /** + * Verifies a digital signature (created with the sign method) and returns + * the boolean result. *

    * Limitations: A new public/private key pair used for ESAPI 2.0 digital * signatures with this method and {@link #sign(String)} @@ -238,79 +238,79 @@ CipherText encrypt(SecretKey key, PlainText plaintext) * can not be used with expected results across JVM instances. This limitation * will be addressed in ESAPI 2.1. *

    - * @param signature - * the signature to verify against 'data' - * @param data - * the data to verify against 'signature' - * - * @return - * true, if the signature is verified, false otherwise - */ - boolean verifySignature(String signature, String data); + * @param signature + * the signature to verify against 'data' + * @param data + * the data to verify against 'signature' + * + * @return + * true, if the signature is verified, false otherwise + */ + boolean verifySignature(String signature, String data); - /** - * Creates a seal that binds a set of data and includes an expiration timestamp. - * - * @param data - * the data to seal - * @param timestamp - * the absolute expiration date of the data, expressed as seconds since the epoch - * - * @return - * the seal - * + /** + * Creates a seal that binds a set of data and includes an expiration timestamp. + * + * @param data + * the data to seal + * @param timestamp + * the absolute expiration date of the data, expressed as seconds since the epoch + * + * @return + * the seal + * * @throws IntegrityException - */ - String seal(String data, long timestamp) throws IntegrityException; + */ + String seal(String data, long timestamp) throws IntegrityException; - /** - * Unseals data (created with the seal method) and throws an exception - * describing any of the various problems that could exist with a seal, such - * as an invalid seal format, expired timestamp, or decryption error. - * - * @param seal - * the sealed data - * - * @return - * the original (unsealed) data - * - * @throws EncryptionException - * if the unsealed data cannot be retrieved for any reason - */ - String unseal( String seal ) throws EncryptionException; - - /** - * Verifies a seal (created with the seal method) and throws an exception - * describing any of the various problems that could exist with a seal, such - * as an invalid seal format, expired timestamp, or data mismatch. - * - * @param seal - * the seal to verify - * - * @return - * true, if the seal is valid. False otherwise - */ - boolean verifySeal(String seal); - - /** - * Gets an absolute timestamp representing an offset from the current time to be used by - * other functions in the library. - * - * @param offset - * the offset to add to the current time - * - * @return - * the absolute timestamp - */ - long getRelativeTimeStamp( long offset ); - - /** - * Gets a timestamp representing the current date and time to be used by - * other functions in the library. - * - * @return - * a timestamp representing the current time - */ - long getTimeStamp(); + /** + * Unseals data (created with the seal method) and throws an exception + * describing any of the various problems that could exist with a seal, such + * as an invalid seal format, expired timestamp, or decryption error. + * + * @param seal + * the sealed data + * + * @return + * the original (unsealed) data + * + * @throws EncryptionException + * if the unsealed data cannot be retrieved for any reason + */ + String unseal( String seal ) throws EncryptionException; + + /** + * Verifies a seal (created with the seal method) and throws an exception + * describing any of the various problems that could exist with a seal, such + * as an invalid seal format, expired timestamp, or data mismatch. + * + * @param seal + * the seal to verify + * + * @return + * true, if the seal is valid. False otherwise + */ + boolean verifySeal(String seal); + + /** + * Gets an absolute timestamp representing an offset from the current time to be used by + * other functions in the library. + * + * @param offset + * the offset to add to the current time + * + * @return + * the absolute timestamp + */ + long getRelativeTimeStamp( long offset ); + + /** + * Gets a timestamp representing the current date and time to be used by + * other functions in the library. + * + * @return + * a timestamp representing the current time + */ + long getTimeStamp(); } \ No newline at end of file diff --git a/src/main/java/org/owasp/esapi/ExecuteResult.java b/src/main/java/org/owasp/esapi/ExecuteResult.java index e9835e300..33bf0b13c 100644 --- a/src/main/java/org/owasp/esapi/ExecuteResult.java +++ b/src/main/java/org/owasp/esapi/ExecuteResult.java @@ -26,50 +26,50 @@ */ public class ExecuteResult { - private final int exitValue; - private final String output; - private final String errors; + private final int exitValue; + private final String output; + private final String errors; - /** - * Constructs an ExecuteResult from the given values. - * - * @param exitValue - * the code from java.lang.Process.exitValue() - * @param output - * the contents read from java.lang.Process.getInputStream() - * @param errors - * the contents read from java.lang.Process.getErrorStream() - */ - public ExecuteResult(int exitValue, String output, String errors) { - this.exitValue = exitValue; - this.output = output; - this.errors = errors; - } + /** + * Constructs an ExecuteResult from the given values. + * + * @param exitValue + * the code from java.lang.Process.exitValue() + * @param output + * the contents read from java.lang.Process.getInputStream() + * @param errors + * the contents read from java.lang.Process.getErrorStream() + */ + public ExecuteResult(int exitValue, String output, String errors) { + this.exitValue = exitValue; + this.output = output; + this.errors = errors; + } - /** - * @return the code from java.lang.Process.exitValue() - */ - public int getExitValue() { - return exitValue; - } + /** + * @return the code from java.lang.Process.exitValue() + */ + public int getExitValue() { + return exitValue; + } - /** - * @return the contents read from java.lang.Process.getInputStream() - */ - public String getOutput() { - return output; - } + /** + * @return the contents read from java.lang.Process.getInputStream() + */ + public String getOutput() { + return output; + } - /** - * @return the contents read from java.lang.Process.getErrorStream() - */ - public String getErrors() { - return errors; - } - - @Override - public String toString() { - return "ExecuteResult[exitValue="+exitValue+",output="+output+",errors="+errors+"]"; - } + /** + * @return the contents read from java.lang.Process.getErrorStream() + */ + public String getErrors() { + return errors; + } + + @Override + public String toString() { + return "ExecuteResult[exitValue="+exitValue+",output="+output+",errors="+errors+"]"; + } } diff --git a/src/main/java/org/owasp/esapi/Executor.java b/src/main/java/org/owasp/esapi/Executor.java index b475da90d..7ad5ba4df 100644 --- a/src/main/java/org/owasp/esapi/Executor.java +++ b/src/main/java/org/owasp/esapi/Executor.java @@ -41,38 +41,38 @@ */ public interface Executor { - /** - * Invokes the specified executable with default workdir and codec and not logging parameters. - * - * @param executable - * the command to execute - * @param params - * the parameters of the command being executed - */ - ExecuteResult executeSystemCommand(File executable, List params) throws ExecutorException; + /** + * Invokes the specified executable with default workdir and codec and not logging parameters. + * + * @param executable + * the command to execute + * @param params + * the parameters of the command being executed + */ + ExecuteResult executeSystemCommand(File executable, List params) throws ExecutorException; - /** - * Executes a system command after checking that the executable exists and - * escaping all the parameters to ensure that injection is impossible. - * Implementations must change to the specified working - * directory before invoking the command. - * - * @param executable - * the command to execute - * @param params - * the parameters of the command being executed - * @param workdir - * the working directory - * @param codec - * the codec to use to encode for the particular OS in use - * @param logParams - * use false if any parameters contains sensitive or confidential information - * - * @return the output of the command being run - * - * @throws ExecutorException - * the service exception - */ - ExecuteResult executeSystemCommand(File executable, List params, File workdir, Codec codec, boolean logParams, boolean redirectErrorStream) throws ExecutorException; + /** + * Executes a system command after checking that the executable exists and + * escaping all the parameters to ensure that injection is impossible. + * Implementations must change to the specified working + * directory before invoking the command. + * + * @param executable + * the command to execute + * @param params + * the parameters of the command being executed + * @param workdir + * the working directory + * @param codec + * the codec to use to encode for the particular OS in use + * @param logParams + * use false if any parameters contains sensitive or confidential information + * + * @return the output of the command being run + * + * @throws ExecutorException + * the service exception + */ + ExecuteResult executeSystemCommand(File executable, List params, File workdir, Codec codec, boolean logParams, boolean redirectErrorStream) throws ExecutorException; } diff --git a/src/main/java/org/owasp/esapi/HTTPUtilities.java b/src/main/java/org/owasp/esapi/HTTPUtilities.java index c1b83f5c4..a4091eda7 100644 --- a/src/main/java/org/owasp/esapi/HTTPUtilities.java +++ b/src/main/java/org/owasp/esapi/HTTPUtilities.java @@ -36,27 +36,27 @@ */ public interface HTTPUtilities { - // All implied static final as this is an interface + // All implied static final as this is an interface String REMEMBER_TOKEN_COOKIE_NAME = "rtoken"; int MAX_COOKIE_LEN = 4096; // From RFC 2109 - int MAX_COOKIE_PAIRS = 20; // From RFC 2109 - String CSRF_TOKEN_NAME = "ctoken"; - String ESAPI_STATE = "estate"; + int MAX_COOKIE_PAIRS = 20; // From RFC 2109 + String CSRF_TOKEN_NAME = "ctoken"; + String ESAPI_STATE = "estate"; - int PARAMETER = 0; - int HEADER = 1; - int COOKIE = 2; + int PARAMETER = 0; + int HEADER = 1; + int COOKIE = 2; - /** + /** * Calls addCookie with the *current* request. * * @param cookie The cookie to add * - * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) + * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) */ void addCookie(Cookie cookie); - /** + /** * Add a cookie to the response after ensuring that there are no encoded or * illegal characters in the name and name and value. This method also sets * the secure and HttpOnly flags on the cookie. @@ -66,7 +66,7 @@ public interface HTTPUtilities */ void addCookie(HttpServletResponse response, Cookie cookie); - /** + /** * Adds the current user's CSRF token (see User.getCSRFToken()) to the URL for purposes of preventing CSRF attacks. * This method should be used on all URLs to be put into all links and forms the application generates. * @@ -78,7 +78,7 @@ public interface HTTPUtilities /** * Calls addHeader with the *current* request. * - * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) + * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) */ void addHeader(String name, String value); @@ -95,49 +95,49 @@ public interface HTTPUtilities */ void addHeader(HttpServletResponse response, String name, String value); - /** + /** * Calls assertSecureRequest with the *current* request. - * @see HTTPUtilities#assertSecureRequest(HttpServletRequest) - * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) - */ - void assertSecureRequest() throws AccessControlException; + * @see HTTPUtilities#assertSecureRequest(HttpServletRequest) + * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) + */ + void assertSecureRequest() throws AccessControlException; - /** + /** * Calls assertSecureChannel with the *current* request. - * @see HTTPUtilities#assertSecureChannel(HttpServletRequest) - * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) - */ - void assertSecureChannel() throws AccessControlException; + * @see HTTPUtilities#assertSecureChannel(HttpServletRequest) + * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) + */ + void assertSecureChannel() throws AccessControlException; - /** - * Ensures that the request uses both SSL and POST to protect any sensitive parameters - * in the querystring from being sniffed, logged, bookmarked, included in referer header, etc... - * This method should be called for any request that contains sensitive data from a web form. + /** + * Ensures that the request uses both SSL and POST to protect any sensitive parameters + * in the querystring from being sniffed, logged, bookmarked, included in referer header, etc... + * This method should be called for any request that contains sensitive data from a web form. * * @param request * @throws AccessControlException if security constraints are not met - */ + */ void assertSecureRequest(HttpServletRequest request) throws AccessControlException; - /** - * Ensures the use of SSL to protect any sensitive parameters in the request and - * any sensitive data in the response. This method should be called for any request - * that contains sensitive data from a web form or will result in sensitive data in the - * response page. + /** + * Ensures the use of SSL to protect any sensitive parameters in the request and + * any sensitive data in the response. This method should be called for any request + * that contains sensitive data from a web form or will result in sensitive data in the + * response page. * * @param request * @throws AccessControlException if security constraints are not met - */ + */ void assertSecureChannel(HttpServletRequest request) throws AccessControlException; - /** + /** * Calls changeSessionIdentifier with the *current* request. * - * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) + * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) */ - HttpSession changeSessionIdentifier() throws AuthenticationException; + HttpSession changeSessionIdentifier() throws AuthenticationException; - /** + /** * Invalidate the existing session after copying all of its contents to a newly created session with a new session id. * Note that this is different from logging out and creating a new session identifier that does not contain the * existing session contents. Care should be taken to use this only when the existing session does not contain @@ -150,34 +150,34 @@ public interface HTTPUtilities HttpSession changeSessionIdentifier(HttpServletRequest request) throws AuthenticationException; /** - * Clears the current HttpRequest and HttpResponse associated with the current thread. + * Clears the current HttpRequest and HttpResponse associated with the current thread. * - * @see ESAPI#clearCurrent() - */ + * @see ESAPI#clearCurrent() + */ void clearCurrent(); /** - * Decrypts an encrypted hidden field value and returns the cleartext. If the field does not decrypt properly, - * an IntrusionException is thrown to indicate tampering. + * Decrypts an encrypted hidden field value and returns the cleartext. If the field does not decrypt properly, + * an IntrusionException is thrown to indicate tampering. * - * @param encrypted hidden field value to decrypt - * @return decrypted hidden field value stored as a String - */ - String decryptHiddenField(String encrypted); + * @param encrypted hidden field value to decrypt + * @return decrypted hidden field value stored as a String + */ + String decryptHiddenField(String encrypted); /** - * Takes an encrypted querystring and returns a Map containing the original parameters. + * Takes an encrypted querystring and returns a Map containing the original parameters. * - * @param encrypted the encrypted querystring to decrypt - * @return a Map object containing the decrypted querystring - * @throws EncryptionException - */ + * @param encrypted the encrypted querystring to decrypt + * @return a Map object containing the decrypted querystring + * @throws EncryptionException + */ Map decryptQueryString(String encrypted) throws EncryptionException; /** * Calls decryptStateFromCookie with the *current* request. * - * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) + * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) */ Map decryptStateFromCookie() throws EncryptionException; @@ -186,7 +186,7 @@ public interface HTTPUtilities * * @param request * @return a map containing the decrypted cookie state value - * @throws EncryptionException + * @throws EncryptionException */ Map decryptStateFromCookie(HttpServletRequest request) throws EncryptionException; @@ -197,22 +197,22 @@ public interface HTTPUtilities * @return the encrypted value of the hidden field * @throws EncryptionException */ - String encryptHiddenField(String value) throws EncryptionException; + String encryptHiddenField(String value) throws EncryptionException; - /** - * Takes a querystring (everything after the question mark in the URL) and returns an encrypted string containing the parameters. + /** + * Takes a querystring (everything after the question mark in the URL) and returns an encrypted string containing the parameters. * - * @param query the querystring to encrypt - * @return encrypted querystring stored as a String - * @throws EncryptionException - */ - String encryptQueryString(String query) throws EncryptionException; + * @param query the querystring to encrypt + * @return encrypted querystring stored as a String + * @throws EncryptionException + */ + String encryptQueryString(String query) throws EncryptionException; - /** - * Calls encryptStateInCookie with the *current* response. + /** + * Calls encryptStateInCookie with the *current* response. * - * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) - */ + * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) + */ void encryptStateInCookie(Map cleartext) throws EncryptionException; /** @@ -229,28 +229,28 @@ public interface HTTPUtilities void encryptStateInCookie(HttpServletResponse response, Map cleartext) throws EncryptionException; /** - * Calls getCookie with the *current* response. - * - * @param name The cookie to get + * Calls getCookie with the *current* response. + * + * @param name The cookie to get * @return the requested cookie value * @throws ValidationException * - * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) - */ - String getCookie(String name) throws ValidationException; + * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) + */ + String getCookie(String name) throws ValidationException; - /** + /** * A safer replacement for getCookies() in HttpServletRequest that returns the canonicalized * value of the named cookie after "global" validation against the * general type defined in ESAPI.properties. This should not be considered a replacement for * more specific validation. * * @param request - * @param name The cookie to get + * @param name The cookie to get * @return the requested cookie value * @throws ValidationException */ - String getCookie(HttpServletRequest request, String name) throws ValidationException; + String getCookie(HttpServletRequest request, String name) throws ValidationException; /** * Returns the current user's CSRF token. If there is no current user then return null. @@ -259,44 +259,44 @@ public interface HTTPUtilities */ String getCSRFToken(); - /** + /** * Retrieves the current HttpServletRequest * * @return the current request */ HttpServletRequest getCurrentRequest(); - /** + /** * Retrieves the current HttpServletResponse * * @return the current response */ HttpServletResponse getCurrentResponse(); - /** - * Calls getFileUploads with the *current* request, default upload directory, and default allowed file extensions + /** + * Calls getFileUploads with the *current* request, default upload directory, and default allowed file extensions * * @return List of new File objects from upload * @throws ValidationException if the file fails validation * - * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) - */ - List getFileUploads() throws ValidationException; + * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) + */ + List getFileUploads() throws ValidationException; /** - * Call getFileUploads with the specified request, default upload directory, and default allowed file extensions + * Call getFileUploads with the specified request, default upload directory, and default allowed file extensions * * @return List of new File objects from upload * @throws ValidationException if the file fails validation - */ - List getFileUploads(HttpServletRequest request) throws ValidationException; + */ + List getFileUploads(HttpServletRequest request) throws ValidationException; /** - * Call getFileUploads with the specified request, specified upload directory, and default allowed file extensions + * Call getFileUploads with the specified request, specified upload directory, and default allowed file extensions * * @return List of new File objects from upload * @throws ValidationException if the file fails validation - */ + */ List getFileUploads(HttpServletRequest request, File finalDir) throws ValidationException; @@ -306,7 +306,7 @@ public interface HTTPUtilities * possibly virus checking, and path and name checks. Refer to the file checking methods in Validator for more * information. *

    - * This method uses {@link HTTPUtilities#getCurrentRequest()} to obtain the {@link HttpServletRequest} object + * This method uses {@link HTTPUtilities#getCurrentRequest()} to obtain the {@link HttpServletRequest} object * * @param request * @return List of new File objects from upload @@ -315,12 +315,12 @@ public interface HTTPUtilities List getFileUploads(HttpServletRequest request, File destinationDir, List allowedExtensions) throws ValidationException; - /** - * Calls getHeader with the *current* request. + /** + * Calls getHeader with the *current* request. * - * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) - */ - String getHeader(String name) throws ValidationException; + * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) + */ + String getHeader(String name) throws ValidationException; /** * A safer replacement for getHeader() in HttpServletRequest that returns the canonicalized @@ -332,14 +332,14 @@ public interface HTTPUtilities * @param name * @return the requested header value */ - String getHeader(HttpServletRequest request, String name) throws ValidationException; + String getHeader(HttpServletRequest request, String name) throws ValidationException; - /** - * Calls getParameter with the *current* request. + /** + * Calls getParameter with the *current* request. * - * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) - */ - String getParameter(String name) throws ValidationException; + * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) + */ + String getParameter(String name) throws ValidationException; /** * A safer replacement for getParameter() in HttpServletRequest that returns the canonicalized @@ -353,12 +353,12 @@ public interface HTTPUtilities */ String getParameter(HttpServletRequest request, String name) throws ValidationException; - /** - * Calls killAllCookies with the *current* request and response. + /** + * Calls killAllCookies with the *current* request and response. * - * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) - */ - void killAllCookies(); + * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) + */ + void killAllCookies(); /** * Kill all cookies received in the last request from the browser. Note that new cookies set by the application in @@ -369,12 +369,12 @@ public interface HTTPUtilities */ void killAllCookies(HttpServletRequest request, HttpServletResponse response); - /** - * Calls killCookie with the *current* request and response. + /** + * Calls killCookie with the *current* request and response. * - * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) - */ - void killCookie(String name); + * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) + */ + void killCookie(String name); /** * Kills the specified cookie by setting a new cookie that expires immediately. Note that this @@ -386,12 +386,12 @@ public interface HTTPUtilities */ void killCookie(HttpServletRequest request, HttpServletResponse response, String name); - /** - * Calls logHTTPRequest with the *current* request and logger. + /** + * Calls logHTTPRequest with the *current* request and logger. * - * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) - */ - void logHTTPRequest(); + * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) + */ + void logHTTPRequest(); /** * Format the Source IP address, URL, URL parameters, and all form @@ -420,11 +420,11 @@ public interface HTTPUtilities */ void logHTTPRequest(HttpServletRequest request, Logger logger, List parameterNamesToObfuscate); - /** - * Calls sendForward with the *current* request and response. + /** + * Calls sendForward with the *current* request and response. * - * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) - */ + * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) + */ void sendForward(String location) throws AccessControlException, ServletException, IOException; /** @@ -443,11 +443,11 @@ public interface HTTPUtilities void sendForward(HttpServletRequest request, HttpServletResponse response, String location) throws AccessControlException, ServletException, IOException; - /** - * Calls sendRedirect with the *current* response. + /** + * Calls sendRedirect with the *current* response. * - * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) - */ + * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) + */ void sendRedirect(String location) throws AccessControlException, IOException; @@ -464,25 +464,25 @@ public interface HTTPUtilities */ void sendRedirect(HttpServletResponse response, String location) throws AccessControlException, IOException; - /** - * Calls setContentType with the *current* request and response. + /** + * Calls setContentType with the *current* request and response. * - * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) - */ + * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) + */ void setContentType(); /** - * Set the content type character encoding header on every HttpServletResponse in order to limit - * the ways in which the input data can be represented. This prevents - * malicious users from using encoding and multi-byte escape sequences to - * bypass input validation routines. + * Set the content type character encoding header on every HttpServletResponse in order to limit + * the ways in which the input data can be represented. This prevents + * malicious users from using encoding and multi-byte escape sequences to + * bypass input validation routines. *

    - * Implementations of this method should set the content type header to a safe value for your environment. + * Implementations of this method should set the content type header to a safe value for your environment. * The default is text/html; charset=UTF-8 character encoding, which is the default in early - * versions of HTML and HTTP. See RFC 2047 (http://ds.internic.net/rfc/rfc2045.txt) for more - * information about character encoding and MIME. + * versions of HTML and HTTP. See RFC 2047 (http://ds.internic.net/rfc/rfc2045.txt) for more + * information about character encoding and MIME. *

    - * The DefaultHTTPUtilities reference implementation sets the content type as specified. + * The DefaultHTTPUtilities reference implementation sets the content type as specified. * * @param response The servlet response to set the content type for. */ @@ -498,11 +498,11 @@ public interface HTTPUtilities void setCurrentHTTP(HttpServletRequest request, HttpServletResponse response); - /** - * Calls setHeader with the *current* response. + /** + * Calls setHeader with the *current* response. * - * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) - */ + * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) + */ void setHeader(String name, String value); /** @@ -518,11 +518,11 @@ public interface HTTPUtilities void setHeader(HttpServletResponse response, String name, String value); - /** - * Calls setNoCacheHeaders with the *current* response. + /** + * Calls setNoCacheHeaders with the *current* response. * - * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) - */ + * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) + */ void setNoCacheHeaders(); @@ -556,14 +556,14 @@ public interface HTTPUtilities */ void setNoCacheHeaders(HttpServletResponse response); - /** - * Calls setNoCacheHeaders with the *current* response. - * - * ~DEPRECATED~ Per Kevin Wall, storing passwords with reversible encryption is contrary to *many* - * company's stated security policies. + /** + * Calls setNoCacheHeaders with the *current* response. + * + * ~DEPRECATED~ Per Kevin Wall, storing passwords with reversible encryption is contrary to *many* + * company's stated security policies. * - * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) - */ + * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) + */ @Deprecated String setRememberToken(String password, int maxAge, String domain, String path); @@ -574,49 +574,49 @@ public interface HTTPUtilities /** - * Set a cookie containing the current User's remember me token for automatic authentication. The use of remember me tokens - * is generally not recommended, but this method will help do it as safely as possible. The user interface should strongly warn + * Set a cookie containing the current User's remember me token for automatic authentication. The use of remember me tokens + * is generally not recommended, but this method will help do it as safely as possible. The user interface should strongly warn * the user that this should only be enabled on computers where no other users will have access. *

    * Implementations should save the user's remember me data in an encrypted cookie and send it to the user. * Any old remember me cookie should be destroyed first. Setting this cookie should keep the user - * logged in until the maxAge passes, the password is changed, or the cookie is deleted. - * If the cookie exists for the current user, it should automatically be used by ESAPI to + * logged in until the maxAge passes, the password is changed, or the cookie is deleted. + * If the cookie exists for the current user, it should automatically be used by ESAPI to * log the user in, if the data is valid and not expired. *

    - * The ESAPI reference implementation, DefaultHTTPUtilities.setRememberToken() implements all these suggestions. + * The ESAPI reference implementation, DefaultHTTPUtilities.setRememberToken() implements all these suggestions. *

    * The username can be retrieved with: User username = ESAPI.authenticator().getCurrentUser(); * *~DEPRECATED~ Per Kevin Wall, storing passwords with reversible encryption is contrary to *many* - * company's stated security policies. + * company's stated security policies. * * @param request * @param password the user's password * @param response * @param maxAge the length of time that the token should be valid for in relative seconds - * @param domain the domain to restrict the token to or null - * @param path the path to restrict the token to or null - * @return encrypted "Remember Me" token stored as a String - */ + * @param domain the domain to restrict the token to or null + * @param path the path to restrict the token to or null + * @return encrypted "Remember Me" token stored as a String + */ @Deprecated String setRememberToken(HttpServletRequest request, HttpServletResponse response, String password, int maxAge, String domain, String path); - /** - * Calls verifyCSRFToken with the *current* request. + /** + * Calls verifyCSRFToken with the *current* request. * - * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) - */ + * @see HTTPUtilities#setCurrentHTTP(HttpServletRequest, HttpServletResponse) + */ void verifyCSRFToken(); /** * Checks the CSRF token in the URL (see User.getCSRFToken()) against the user's CSRF token and - * throws an IntrusionException if it is missing. + * throws an IntrusionException if it is missing. * * @param request * @throws IntrusionException if CSRF token is missing or incorrect - */ + */ void verifyCSRFToken(HttpServletRequest request) throws IntrusionException; /** diff --git a/src/main/java/org/owasp/esapi/IntrusionDetector.java b/src/main/java/org/owasp/esapi/IntrusionDetector.java index 6a14ec3c3..2a1388332 100644 --- a/src/main/java/org/owasp/esapi/IntrusionDetector.java +++ b/src/main/java/org/owasp/esapi/IntrusionDetector.java @@ -38,10 +38,10 @@ public interface IntrusionDetector { * the current user's security exceptions. If the User has reached any security thresholds, the appropriate security action can be taken and logged. * * @param exception - * the exception thrown + * the exception thrown * * @throws IntrusionException - * the intrusion exception + * the intrusion exception */ void addException(Exception exception) throws IntrusionException; @@ -51,12 +51,12 @@ public interface IntrusionDetector { * the current user's security event. If the User has reached any security thresholds, the appropriate security action can be taken and logged. * * @param eventName - * the event to add + * the event to add * @param logMessage - * the message to log with the event + * the message to log with the event * * @throws IntrusionException - * the intrusion exception + * the intrusion exception */ void addEvent(String eventName, String logMessage) throws IntrusionException; diff --git a/src/main/java/org/owasp/esapi/LogFactory.java b/src/main/java/org/owasp/esapi/LogFactory.java index e3736986d..edde286c2 100644 --- a/src/main/java/org/owasp/esapi/LogFactory.java +++ b/src/main/java/org/owasp/esapi/LogFactory.java @@ -28,33 +28,33 @@ * */ public interface LogFactory { - - /** - * Gets the logger associated with the specified module name. The module name is used by the logger to log which - * module is generating the log events. The implementation of this method should return any preexisting Logger - * associated with this module name, rather than creating a new Logger. - *

    - * The JavaLogFactory reference implementation meets these requirements. - * - * @param moduleName - * The name of the module requesting the logger. - * @return - * The Logger associated with this module. - */ - Logger getLogger(String moduleName); - - /** - * Gets the logger associated with the specified class. The class is used by the logger to log which - * class is generating the log events. The implementation of this method should return any preexisting Logger - * associated with this class name, rather than creating a new Logger. - *

    - * The JavaLogFactory reference implementation meets these requirements. - * - * @param clazz - * The name of the class requesting the logger. - * @return - * The Logger associated with this class. - */ - Logger getLogger(Class clazz); - + + /** + * Gets the logger associated with the specified module name. The module name is used by the logger to log which + * module is generating the log events. The implementation of this method should return any preexisting Logger + * associated with this module name, rather than creating a new Logger. + *

    + * The JavaLogFactory reference implementation meets these requirements. + * + * @param moduleName + * The name of the module requesting the logger. + * @return + * The Logger associated with this module. + */ + Logger getLogger(String moduleName); + + /** + * Gets the logger associated with the specified class. The class is used by the logger to log which + * class is generating the log events. The implementation of this method should return any preexisting Logger + * associated with this class name, rather than creating a new Logger. + *

    + * The JavaLogFactory reference implementation meets these requirements. + * + * @param clazz + * The name of the class requesting the logger. + * @return + * The Logger associated with this class. + */ + Logger getLogger(Class clazz); + } diff --git a/src/main/java/org/owasp/esapi/Logger.java b/src/main/java/org/owasp/esapi/Logger.java index 2e3ec3399..0f41e7376 100644 --- a/src/main/java/org/owasp/esapi/Logger.java +++ b/src/main/java/org/owasp/esapi/Logger.java @@ -92,89 +92,89 @@ */ public interface Logger { - // All implied static final as this is an interface - - /** + // All implied static final as this is an interface + + /** * A security type of log event that has succeeded. This is one of 6 predefined * ESAPI logging events. New events can be added. */ - EventType SECURITY_SUCCESS = new EventType( "SECURITY SUCCESS", true); + EventType SECURITY_SUCCESS = new EventType( "SECURITY SUCCESS", true); - /** + /** * A security type of log event that has failed. This is one of 6 predefined * ESAPI logging events. New events can be added. */ - EventType SECURITY_FAILURE = new EventType( "SECURITY FAILURE", false); + EventType SECURITY_FAILURE = new EventType( "SECURITY FAILURE", false); - /** - * A security type of log event that is associated with an audit trail of some type, - * but the log event is not specifically something that has either succeeded or failed - * or that is irrelevant in the case of this logged message. - */ - // CHECKME: Should the Boolean for this be 'null' or 'true'? See EVENT_UNSPECIFIED. - EventType SECURITY_AUDIT = new EventType( "SECURITY AUDIT", null); + /** + * A security type of log event that is associated with an audit trail of some type, + * but the log event is not specifically something that has either succeeded or failed + * or that is irrelevant in the case of this logged message. + */ + // CHECKME: Should the Boolean for this be 'null' or 'true'? See EVENT_UNSPECIFIED. + EventType SECURITY_AUDIT = new EventType( "SECURITY AUDIT", null); - /** + /** * A non-security type of log event that has succeeded. This is one of 6 predefined * ESAPI logging events. New events can be added. */ - EventType EVENT_SUCCESS = new EventType( "EVENT SUCCESS", true); - - /** + EventType EVENT_SUCCESS = new EventType( "EVENT SUCCESS", true); + + /** * A non-security type of log event that has failed. This is one of 6 predefined * ESAPI logging events. New events can be added. */ - EventType EVENT_FAILURE = new EventType( "EVENT FAILURE", false); + EventType EVENT_FAILURE = new EventType( "EVENT FAILURE", false); - /** + /** * A non-security type of log event that is unspecified. This is one of 6 predefined * ESAPI logging events. New events can be added. */ - EventType EVENT_UNSPECIFIED = new EventType( "EVENT UNSPECIFIED", null); + EventType EVENT_UNSPECIFIED = new EventType( "EVENT UNSPECIFIED", null); - /** - * Defines the type of log event that is being generated. The Logger interface defines 6 types of Log events: - * SECURITY_SUCCESS, SECURITY_FAILURE, EVENT_SUCCESS, EVENT_FAILURE, EVENT_UNSPECIFIED. + /** + * Defines the type of log event that is being generated. The Logger interface defines 6 types of Log events: + * SECURITY_SUCCESS, SECURITY_FAILURE, EVENT_SUCCESS, EVENT_FAILURE, EVENT_UNSPECIFIED. * Your implementation can extend or change this list if desired. - */ - class EventType { - - private String type; - private Boolean success = null; - - public EventType (String name, Boolean newSuccess) { - this.type = name; - this.success = newSuccess; - } - - public Boolean isSuccess() { - return success; - } - + */ + class EventType { + + private String type; + private Boolean success = null; + + public EventType (String name, Boolean newSuccess) { + this.type = name; + this.success = newSuccess; + } + + public Boolean isSuccess() { + return success; + } + /** * Convert the {@code EventType} to a string. * @return The event type name. */ - @Override + @Override public String toString() { - return this.type; - } - } - - /* + return this.type; + } + } + + /* * The Logger interface defines 6 logging levels: FATAL, ERROR, WARNING, INFO, DEBUG, TRACE. It also * supports ALL, which logs all events, and OFF, which disables all logging. * Your implementation can extend or change this list if desired. */ - - /** OFF indicates that no messages should be logged. This level is initialized to Integer.MAX_VALUE. */ - int OFF = Integer.MAX_VALUE; + + /** OFF indicates that no messages should be logged. This level is initialized to Integer.MAX_VALUE. */ + int OFF = Integer.MAX_VALUE; - /** FATAL indicates that only FATAL messages should be logged. This level is initialized to 1000. */ - int FATAL = 1000; + /** FATAL indicates that only FATAL messages should be logged. This level is initialized to 1000. */ + int FATAL = 1000; - /** ERROR indicates that ERROR messages and above should be logged. - * This level is initialized to 800. */ + /** ERROR indicates that ERROR messages and above should be logged. + * This level is initialized to 800. */ int ERROR = 800; /** WARNING indicates that WARNING messages and above should be logged. @@ -213,216 +213,216 @@ public String toString() { */ int getESAPILevel(); - /** + /** * Log a fatal event if 'fatal' level logging is enabled. * * @param type - * the type of event + * the type of event * @param message - * the message to log + * the message to log */ - void fatal(EventType type, String message); - - /** + void fatal(EventType type, String message); + + /** * Log a fatal level security event if 'fatal' level logging is enabled * and also record the stack trace associated with the event. * * @param type - * the type of event + * the type of event * @param message - * the message to log + * the message to log * @param throwable - * the exception to be logged + * the exception to be logged */ - void fatal(EventType type, String message, Throwable throwable); + void fatal(EventType type, String message, Throwable throwable); - /** - * Allows the caller to determine if messages logged at this level - * will be discarded, to avoid performing expensive processing. - * - * @return true if fatal level messages will be output to the log - */ - boolean isFatalEnabled(); + /** + * Allows the caller to determine if messages logged at this level + * will be discarded, to avoid performing expensive processing. + * + * @return true if fatal level messages will be output to the log + */ + boolean isFatalEnabled(); - /** + /** * Log an error level security event if 'error' level logging is enabled. * * @param type - * the type of event + * the type of event * @param message - * the message to log + * the message to log */ - void error(EventType type, String message); - - /** + void error(EventType type, String message); + + /** * Log an error level security event if 'error' level logging is enabled * and also record the stack trace associated with the event. * * @param type - * the type of event + * the type of event * @param message - * the message to log + * the message to log * @param throwable - * the exception to be logged + * the exception to be logged */ - void error(EventType type, String message, Throwable throwable); + void error(EventType type, String message, Throwable throwable); - /** - * Allows the caller to determine if messages logged at this level - * will be discarded, to avoid performing expensive processing. - * - * @return true if error level messages will be output to the log - */ - boolean isErrorEnabled(); + /** + * Allows the caller to determine if messages logged at this level + * will be discarded, to avoid performing expensive processing. + * + * @return true if error level messages will be output to the log + */ + boolean isErrorEnabled(); - /** + /** * Log a warning level security event if 'warning' level logging is enabled. * * @param type - * the type of event + * the type of event * @param message - * the message to log + * the message to log */ - void warning(EventType type, String message); - - /** + void warning(EventType type, String message); + + /** * Log a warning level security event if 'warning' level logging is enabled * and also record the stack trace associated with the event. * * @param type - * the type of event + * the type of event * @param message - * the message to log + * the message to log * @param throwable - * the exception to be logged + * the exception to be logged */ - void warning(EventType type, String message, Throwable throwable); + void warning(EventType type, String message, Throwable throwable); - /** - * Allows the caller to determine if messages logged at this level - * will be discarded, to avoid performing expensive processing. - * - * @return true if warning level messages will be output to the log - */ - boolean isWarningEnabled(); + /** + * Allows the caller to determine if messages logged at this level + * will be discarded, to avoid performing expensive processing. + * + * @return true if warning level messages will be output to the log + */ + boolean isWarningEnabled(); - /** + /** * Log an info level security event if 'info' level logging is enabled. * * @param type - * the type of event + * the type of event * @param message - * the message to log + * the message to log */ - void info(EventType type, String message); - - /** + void info(EventType type, String message); + + /** * Log an info level security event if 'info' level logging is enabled * and also record the stack trace associated with the event. * * @param type - * the type of event + * the type of event * @param message - * the message to log + * the message to log * @param throwable - * the exception to be logged + * the exception to be logged */ - void info(EventType type, String message, Throwable throwable); + void info(EventType type, String message, Throwable throwable); - /** - * Allows the caller to determine if messages logged at this level - * will be discarded, to avoid performing expensive processing. - * - * @return true if info level messages will be output to the log - */ - boolean isInfoEnabled(); + /** + * Allows the caller to determine if messages logged at this level + * will be discarded, to avoid performing expensive processing. + * + * @return true if info level messages will be output to the log + */ + boolean isInfoEnabled(); - /** + /** * Log a debug level security event if 'debug' level logging is enabled. * * @param type - * the type of event + * the type of event * @param message - * the message to log + * the message to log */ - void debug(EventType type, String message); - - /** + void debug(EventType type, String message); + + /** * Log a debug level security event if 'debug' level logging is enabled * and also record the stack trace associated with the event. * * @param type - * the type of event + * the type of event * @param message - * the message to log + * the message to log * @param throwable - * the exception to be logged + * the exception to be logged */ - void debug(EventType type, String message, Throwable throwable); + void debug(EventType type, String message, Throwable throwable); - /** - * Allows the caller to determine if messages logged at this level - * will be discarded, to avoid performing expensive processing. - * - * @return true if debug level messages will be output to the log - */ - boolean isDebugEnabled(); + /** + * Allows the caller to determine if messages logged at this level + * will be discarded, to avoid performing expensive processing. + * + * @return true if debug level messages will be output to the log + */ + boolean isDebugEnabled(); - /** + /** * Log a trace level security event if 'trace' level logging is enabled. * * @param type - * the type of event + * the type of event * @param message - * the message to log + * the message to log */ - void trace(EventType type, String message); - - /** + void trace(EventType type, String message); + + /** * Log a trace level security event if 'trace' level logging is enabled * and also record the stack trace associated with the event. * * @param type - * the type of event + * the type of event * @param message - * the message to log + * the message to log * @param throwable - * the exception to be logged + * the exception to be logged */ - void trace(EventType type, String message, Throwable throwable); + void trace(EventType type, String message, Throwable throwable); - /** - * Allows the caller to determine if messages logged at this level - * will be discarded, to avoid performing expensive processing. - * - * @return true if trace level messages will be output to the log - */ - boolean isTraceEnabled(); + /** + * Allows the caller to determine if messages logged at this level + * will be discarded, to avoid performing expensive processing. + * + * @return true if trace level messages will be output to the log + */ + boolean isTraceEnabled(); - /** + /** * Log an event regardless of what logging level is enabled. *
    * Note that logging will not occur if the underlying logging implementation has logging disabled. * * @param type - * the type of event + * the type of event * @param message - * the message to log + * the message to log */ - void always(EventType type, String message); - - /** + void always(EventType type, String message); + + /** * Log an event regardless of what logging level is enabled * and also record the stack trace associated with the event. *
    * Note that logging will not occur if the underlying logging implementation has logging disabled. * * @param type - * the type of event + * the type of event * @param message - * the message to log + * the message to log * @param throwable - * the exception to be logged + * the exception to be logged */ - void always(EventType type, String message, Throwable throwable); + void always(EventType type, String message, Throwable throwable); } diff --git a/src/main/java/org/owasp/esapi/PreparedString.java b/src/main/java/org/owasp/esapi/PreparedString.java index ba26087f6..d0695e4a5 100644 --- a/src/main/java/org/owasp/esapi/PreparedString.java +++ b/src/main/java/org/owasp/esapi/PreparedString.java @@ -38,100 +38,100 @@ * @since June 1, 2007 */ public class PreparedString { - char parameterCharacter = '?'; - Codec codec = null; - String[] parameters = null; - ArrayList parts = new ArrayList(); - private final static char[] IMMUNE = {}; + char parameterCharacter = '?'; + Codec codec = null; + String[] parameters = null; + ArrayList parts = new ArrayList(); + private final static char[] IMMUNE = {}; - /** - * Create a PreparedString with the supplied template and Codec. The template should use the - * default parameter placeholder character (?) in the place where actual parameters are to be inserted. - * The supplied Codec will be used to escape characters in calls to set, unless a specific Codec is - * provided to override it. - * @param template - * @param codec - */ - public PreparedString( String template, Codec codec ) { - this.codec = codec; - split( template, parameterCharacter ); - } + /** + * Create a PreparedString with the supplied template and Codec. The template should use the + * default parameter placeholder character (?) in the place where actual parameters are to be inserted. + * The supplied Codec will be used to escape characters in calls to set, unless a specific Codec is + * provided to override it. + * @param template + * @param codec + */ + public PreparedString( String template, Codec codec ) { + this.codec = codec; + split( template, parameterCharacter ); + } - /** - * Create a PreparedString with the supplied template, parameter placeholder character, and Codec. The parameter character - * can be any character, but should not be one that will be used in the template. The parameter character can safely - * be used in a parameter passed into the set methods. - * @param template - * @param parameterCharacter - * @param codec - */ - public PreparedString( String template, char parameterCharacter, Codec codec ) { - this.codec = codec; - this.parameterCharacter = parameterCharacter; - split( template, parameterCharacter ); - } + /** + * Create a PreparedString with the supplied template, parameter placeholder character, and Codec. The parameter character + * can be any character, but should not be one that will be used in the template. The parameter character can safely + * be used in a parameter passed into the set methods. + * @param template + * @param parameterCharacter + * @param codec + */ + public PreparedString( String template, char parameterCharacter, Codec codec ) { + this.codec = codec; + this.parameterCharacter = parameterCharacter; + split( template, parameterCharacter ); + } - /** - * Split a string with a particular character. - * @param str - * @param c - */ - private void split( String str, char c ) { - int index = 0; - int pcount = 0; - for ( int i = 0; i < str.length(); i++ ) { - if ( str.charAt(i) == c ) { - pcount++; - parts.add( str.substring(index,i) ); - index = i + 1; - } - } - parts.add( str.substring(index) ); - parameters = new String[pcount]; - } - - /** - * Set the parameter at index with supplied value using the default Codec to escape. - * @param index - * @param value - */ - public void set( int index, String value ) { - if ( index < 1 || index > parameters.length ) { - throw new IllegalArgumentException( "Attempt to set parameter " + index + " on a PreparedString with only " + parameters.length + " placeholders" ); - } - String encoded = codec.encode( IMMUNE, value ); - parameters[index-1] = encoded; - } - - /** - * Set the parameter at index with supplied value using the supplied Codec to escape. - * @param index - * @param value - * @param codec - */ - public void set( int index, String value, Codec codec ) { - if ( index < 1 || index > parameters.length ) { - throw new IllegalArgumentException( "Attempt to set parameter " + index + " on a PreparedString with only " + parameters.length + " placeholders" ); - } - String encoded = codec.encode( IMMUNE, value ); - parameters[index-1] = encoded; - } - - /** - * Render the PreparedString by combining the template with properly escaped parameters. - */ - public String toString() { - for ( int ix = 0; ix < parameters.length; ix++ ) { - if ( parameters[ix] == null ) { - throw new RuntimeException( "Attempt to render PreparedString without setting parameter " + ( ix + 1 )); - } - } - StringBuilder sb = new StringBuilder(); - int i = 0; - for ( int p=0; p < parts.size(); p++ ) { - sb.append( parts.get( p ) ); - if ( i < parameters.length ) sb.append( parameters[i++] ); - } - return sb.toString(); - } + /** + * Split a string with a particular character. + * @param str + * @param c + */ + private void split( String str, char c ) { + int index = 0; + int pcount = 0; + for ( int i = 0; i < str.length(); i++ ) { + if ( str.charAt(i) == c ) { + pcount++; + parts.add( str.substring(index,i) ); + index = i + 1; + } + } + parts.add( str.substring(index) ); + parameters = new String[pcount]; + } + + /** + * Set the parameter at index with supplied value using the default Codec to escape. + * @param index + * @param value + */ + public void set( int index, String value ) { + if ( index < 1 || index > parameters.length ) { + throw new IllegalArgumentException( "Attempt to set parameter " + index + " on a PreparedString with only " + parameters.length + " placeholders" ); + } + String encoded = codec.encode( IMMUNE, value ); + parameters[index-1] = encoded; + } + + /** + * Set the parameter at index with supplied value using the supplied Codec to escape. + * @param index + * @param value + * @param codec + */ + public void set( int index, String value, Codec codec ) { + if ( index < 1 || index > parameters.length ) { + throw new IllegalArgumentException( "Attempt to set parameter " + index + " on a PreparedString with only " + parameters.length + " placeholders" ); + } + String encoded = codec.encode( IMMUNE, value ); + parameters[index-1] = encoded; + } + + /** + * Render the PreparedString by combining the template with properly escaped parameters. + */ + public String toString() { + for ( int ix = 0; ix < parameters.length; ix++ ) { + if ( parameters[ix] == null ) { + throw new RuntimeException( "Attempt to render PreparedString without setting parameter " + ( ix + 1 )); + } + } + StringBuilder sb = new StringBuilder(); + int i = 0; + for ( int p=0; p < parts.size(); p++ ) { + sb.append( parts.get( p ) ); + if ( i < parameters.length ) sb.append( parameters[i++] ); + } + return sb.toString(); + } } diff --git a/src/main/java/org/owasp/esapi/Randomizer.java b/src/main/java/org/owasp/esapi/Randomizer.java index e1a0b811f..1d991b164 100644 --- a/src/main/java/org/owasp/esapi/Randomizer.java +++ b/src/main/java/org/owasp/esapi/Randomizer.java @@ -30,63 +30,63 @@ */ public interface Randomizer { - /** - * Gets a random string of a desired length and character set. The use of java.security.SecureRandom - * is recommended because it provides a cryptographically strong pseudo-random number generator. - * If SecureRandom is not used, the pseudo-random number generator used should comply with the - * statistical random number generator tests specified in - * FIPS 140-2, Security Requirements for Cryptographic Modules, section 4.9.1. - * - * @param length - * the length of the string - * @param characterSet - * the set of characters to include in the created random string - * - * @return - * the random string of the desired length and character set - */ - String getRandomString(int length, char[] characterSet); + /** + * Gets a random string of a desired length and character set. The use of java.security.SecureRandom + * is recommended because it provides a cryptographically strong pseudo-random number generator. + * If SecureRandom is not used, the pseudo-random number generator used should comply with the + * statistical random number generator tests specified in + * FIPS 140-2, Security Requirements for Cryptographic Modules, section 4.9.1. + * + * @param length + * the length of the string + * @param characterSet + * the set of characters to include in the created random string + * + * @return + * the random string of the desired length and character set + */ + String getRandomString(int length, char[] characterSet); - /** - * Returns a random boolean. The use of java.security.SecureRandom - * is recommended because it provides a cryptographically strong pseudo-random number generator. - * If SecureRandom is not used, the pseudo-random number generator used should comply with the - * statistical random number generator tests specified in - * FIPS 140-2, Security Requirements for Cryptographic Modules, section 4.9.1. - * - * @return - * true or false, randomly - */ - boolean getRandomBoolean(); + /** + * Returns a random boolean. The use of java.security.SecureRandom + * is recommended because it provides a cryptographically strong pseudo-random number generator. + * If SecureRandom is not used, the pseudo-random number generator used should comply with the + * statistical random number generator tests specified in + * FIPS 140-2, Security Requirements for Cryptographic Modules, section 4.9.1. + * + * @return + * true or false, randomly + */ + boolean getRandomBoolean(); - /** - * Gets the random integer in the range of [min, max). The use of java.security.SecureRandom - * is recommended because it provides a cryptographically strong pseudo-random number generator. - * If SecureRandom is not used, the pseudo-random number generator used should comply with the - * statistical random number generator tests specified in - * FIPS 140-2, Security Requirements for Cryptographic Modules, section 4.9.1. - * - * @param min - * the minimum integer that will be returned, inclusive - * @param max - * the maximum integer that will be returned, exclusive - * - * @return - * the random integer - */ - int getRandomInteger(int min, int max); + /** + * Gets the random integer in the range of [min, max). The use of java.security.SecureRandom + * is recommended because it provides a cryptographically strong pseudo-random number generator. + * If SecureRandom is not used, the pseudo-random number generator used should comply with the + * statistical random number generator tests specified in + * FIPS 140-2, Security Requirements for Cryptographic Modules, section 4.9.1. + * + * @param min + * the minimum integer that will be returned, inclusive + * @param max + * the maximum integer that will be returned, exclusive + * + * @return + * the random integer + */ + int getRandomInteger(int min, int max); - /** - * Gets the random long. The use of java.security.SecureRandom - * is recommended because it provides a cryptographically strong pseudo-random number generator. - * If SecureRandom is not used, the pseudo-random number generator used should comply with the - * statistical random number generator tests specified in - * FIPS 140-2, Security Requirements for Cryptographic Modules, section 4.9.1. - * - * @return - * the random long - */ + /** + * Gets the random long. The use of java.security.SecureRandom + * is recommended because it provides a cryptographically strong pseudo-random number generator. + * If SecureRandom is not used, the pseudo-random number generator used should comply with the + * statistical random number generator tests specified in + * FIPS 140-2, Security Requirements for Cryptographic Modules, section 4.9.1. + * + * @return + * the random long + */ long getRandomLong(); @@ -96,30 +96,30 @@ public interface Randomizer { * then merely append "." + extension. * * @param extension - * extension to add to the random filename + * extension to add to the random filename * * @return - * a random unguessable filename ending with the specified extension + * a random unguessable filename ending with the specified extension */ String getRandomFilename( String extension ); - /** - * Gets the random real in the range of [min, max]. The use of java.security.SecureRandom - * is recommended because it provides a cryptographically strong pseudo-random number generator. - * If SecureRandom is not used, the pseudo-random number generator used should comply with the - * statistical random number generator tests specified in - * FIPS 140-2, Security Requirements for Cryptographic Modules, section 4.9.1. - * - * @param min - * the minimum real number that will be returned, inclusive - * @param max - * the maximum real number that will be returned, inclusive - * - * @return - * the random real - */ - float getRandomReal(float min, float max); + /** + * Gets the random real in the range of [min, max]. The use of java.security.SecureRandom + * is recommended because it provides a cryptographically strong pseudo-random number generator. + * If SecureRandom is not used, the pseudo-random number generator used should comply with the + * statistical random number generator tests specified in + * FIPS 140-2, Security Requirements for Cryptographic Modules, section 4.9.1. + * + * @param min + * the minimum real number that will be returned, inclusive + * @param max + * the maximum real number that will be returned, inclusive + * + * @return + * the random real + */ + float getRandomReal(float min, float max); /** * Generates a random GUID. This method could use a hash of random Strings, the current time, @@ -130,16 +130,16 @@ public interface Randomizer { * see the Internet-Draft UUIDs and GUIDs * or the standards body definition at ISO/IEC 11578:1996. * @return - * the GUID + * the GUID * * @throws - * EncryptionException if hashing or encryption fails + * EncryptionException if hashing or encryption fails */ String getRandomGUID() throws EncryptionException; /** * Generates a specified number of random bytes. - * @param n The requested number of random bytes. + * @param n The requested number of random bytes. * @return The {@code n} random bytes are returned. */ byte[] getRandomBytes(int n); diff --git a/src/main/java/org/owasp/esapi/SafeFile.java b/src/main/java/org/owasp/esapi/SafeFile.java index 7df86bb38..fba5a94e7 100644 --- a/src/main/java/org/owasp/esapi/SafeFile.java +++ b/src/main/java/org/owasp/esapi/SafeFile.java @@ -30,78 +30,78 @@ */ public class SafeFile extends File { - private static final long serialVersionUID = 1L; - private static final Pattern PERCENTS_PAT = Pattern.compile("(%)([0-9a-fA-F])([0-9a-fA-F])"); - private static final Pattern FILE_BLACKLIST_PAT = Pattern.compile("([\\\\/:*?<>|^])"); - private static final Pattern DIR_BLACKLIST_PAT = Pattern.compile("([*?<>|^])"); + private static final long serialVersionUID = 1L; + private static final Pattern PERCENTS_PAT = Pattern.compile("(%)([0-9a-fA-F])([0-9a-fA-F])"); + private static final Pattern FILE_BLACKLIST_PAT = Pattern.compile("([\\\\/:*?<>|^])"); + private static final Pattern DIR_BLACKLIST_PAT = Pattern.compile("([*?<>|^])"); - public SafeFile(String path) throws ValidationException { - super(path); - doDirCheck(this.getParent()); - doFileCheck(this.getName()); - } + public SafeFile(String path) throws ValidationException { + super(path); + doDirCheck(this.getParent()); + doFileCheck(this.getName()); + } - public SafeFile(String parent, String child) throws ValidationException { - super(parent, child); - doDirCheck(this.getParent()); - doFileCheck(this.getName()); - } + public SafeFile(String parent, String child) throws ValidationException { + super(parent, child); + doDirCheck(this.getParent()); + doFileCheck(this.getName()); + } - public SafeFile(File parent, String child) throws ValidationException { - super(parent, child); - doDirCheck(this.getParent()); - doFileCheck(this.getName()); - } + public SafeFile(File parent, String child) throws ValidationException { + super(parent, child); + doDirCheck(this.getParent()); + doFileCheck(this.getName()); + } - public SafeFile(URI uri) throws ValidationException { - super(uri); - doDirCheck(this.getParent()); - doFileCheck(this.getName()); - } + public SafeFile(URI uri) throws ValidationException { + super(uri); + doDirCheck(this.getParent()); + doFileCheck(this.getName()); + } - - private void doDirCheck(String path) throws ValidationException { - Matcher m1 = DIR_BLACKLIST_PAT.matcher( path ); - if ( null != m1 && m1.find() ) { - throw new ValidationException( "Invalid directory", "Directory path (" + path + ") contains illegal character: " + m1.group() ); - } + + private void doDirCheck(String path) throws ValidationException { + Matcher m1 = DIR_BLACKLIST_PAT.matcher( path ); + if ( null != m1 && m1.find() ) { + throw new ValidationException( "Invalid directory", "Directory path (" + path + ") contains illegal character: " + m1.group() ); + } - Matcher m2 = PERCENTS_PAT.matcher( path ); - if (null != m2 && m2.find() ) { - throw new ValidationException( "Invalid directory", "Directory path (" + path + ") contains encoded characters: " + m2.group() ); - } - - int ch = containsUnprintableCharacters(path); - if (ch != -1) { - throw new ValidationException("Invalid directory", "Directory path (" + path + ") contains unprintable character: " + ch); - } - } - - private void doFileCheck(String path) throws ValidationException { - Matcher m1 = FILE_BLACKLIST_PAT.matcher( path ); - if ( m1.find() ) { - throw new ValidationException( "Invalid directory", "Directory path (" + path + ") contains illegal character: " + m1.group() ); - } + Matcher m2 = PERCENTS_PAT.matcher( path ); + if (null != m2 && m2.find() ) { + throw new ValidationException( "Invalid directory", "Directory path (" + path + ") contains encoded characters: " + m2.group() ); + } + + int ch = containsUnprintableCharacters(path); + if (ch != -1) { + throw new ValidationException("Invalid directory", "Directory path (" + path + ") contains unprintable character: " + ch); + } + } + + private void doFileCheck(String path) throws ValidationException { + Matcher m1 = FILE_BLACKLIST_PAT.matcher( path ); + if ( m1.find() ) { + throw new ValidationException( "Invalid directory", "Directory path (" + path + ") contains illegal character: " + m1.group() ); + } - Matcher m2 = PERCENTS_PAT.matcher( path ); - if ( m2.find() ) { - throw new ValidationException( "Invalid file", "File path (" + path + ") contains encoded characters: " + m2.group() ); - } - - int ch = containsUnprintableCharacters(path); - if (ch != -1) { - throw new ValidationException("Invalid file", "File path (" + path + ") contains unprintable character: " + ch); - } - } + Matcher m2 = PERCENTS_PAT.matcher( path ); + if ( m2.find() ) { + throw new ValidationException( "Invalid file", "File path (" + path + ") contains encoded characters: " + m2.group() ); + } + + int ch = containsUnprintableCharacters(path); + if (ch != -1) { + throw new ValidationException("Invalid file", "File path (" + path + ") contains unprintable character: " + ch); + } + } - private int containsUnprintableCharacters(String s) { - for (int i = 0; i < s.length(); i++) { - char ch = s.charAt(i); - if (((int) ch) < 32 || ((int) ch) > 126) { - return (int) ch; - } - } - return -1; - } + private int containsUnprintableCharacters(String s) { + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + if (((int) ch) < 32 || ((int) ch) > 126) { + return (int) ch; + } + } + return -1; + } } diff --git a/src/main/java/org/owasp/esapi/SecurityConfiguration.java b/src/main/java/org/owasp/esapi/SecurityConfiguration.java index 27c4af964..2e084a05b 100644 --- a/src/main/java/org/owasp/esapi/SecurityConfiguration.java +++ b/src/main/java/org/owasp/esapi/SecurityConfiguration.java @@ -52,76 +52,76 @@ */ public interface SecurityConfiguration extends EsapiPropertyLoader { - /** - * Gets the application name, used for logging - * - * @return the name of the current application + /** + * Gets the application name, used for logging + * + * @return the name of the current application * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - String getApplicationName(); - - /** - * Returns the fully qualified classname of the ESAPI Logging implementation. + */ + @Deprecated + String getApplicationName(); + + /** + * Returns the fully qualified classname of the ESAPI Logging implementation. * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - String getLogImplementation(); - - /** - * Returns the fully qualified classname of the ESAPI Authentication implementation. + */ + @Deprecated + String getLogImplementation(); + + /** + * Returns the fully qualified classname of the ESAPI Authentication implementation. * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - String getAuthenticationImplementation(); - - /** - * Returns the fully qualified classname of the ESAPI Encoder implementation. + */ + @Deprecated + String getAuthenticationImplementation(); + + /** + * Returns the fully qualified classname of the ESAPI Encoder implementation. * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - String getEncoderImplementation(); - - /** - * Returns the fully qualified classname of the ESAPI Access Control implementation. + */ + @Deprecated + String getEncoderImplementation(); + + /** + * Returns the fully qualified classname of the ESAPI Access Control implementation. * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - String getAccessControlImplementation(); - - /** - * Returns the fully qualified classname of the ESAPI Intrusion Detection implementation. + */ + @Deprecated + String getAccessControlImplementation(); + + /** + * Returns the fully qualified classname of the ESAPI Intrusion Detection implementation. * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - String getIntrusionDetectionImplementation(); - - /** - * Returns the fully qualified classname of the ESAPI Randomizer implementation. + */ + @Deprecated + String getIntrusionDetectionImplementation(); + + /** + * Returns the fully qualified classname of the ESAPI Randomizer implementation. * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - String getRandomizerImplementation(); - - /** - * Returns the fully qualified classname of the ESAPI Encryption implementation. + */ + @Deprecated + String getRandomizerImplementation(); + + /** + * Returns the fully qualified classname of the ESAPI Encryption implementation. * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - String getEncryptionImplementation(); - - /** - * Returns the fully qualified classname of the ESAPI Validation implementation. + */ + @Deprecated + String getEncryptionImplementation(); + + /** + * Returns the fully qualified classname of the ESAPI Validation implementation. * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - String getValidationImplementation(); - - /** - * Returns the validation pattern for a particular type - * @param typeName - * @return the validation pattern - */ + */ + @Deprecated + String getValidationImplementation(); + + /** + * Returns the validation pattern for a particular type + * @param typeName + * @return the validation pattern + */ Pattern getValidationPattern( String typeName ); /** @@ -134,164 +134,164 @@ public interface SecurityConfiguration extends EsapiPropertyLoader { * @see java.text.DateFormat#setLenient(boolean) * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead. */ - @Deprecated + @Deprecated boolean getLenientDatesAccepted(); - - /** - * Returns the fully qualified classname of the ESAPI OS Execution implementation. + + /** + * Returns the fully qualified classname of the ESAPI OS Execution implementation. * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - String getExecutorImplementation(); - - /** - * Returns the fully qualified classname of the ESAPI HTTPUtilities implementation. + */ + @Deprecated + String getExecutorImplementation(); + + /** + * Returns the fully qualified classname of the ESAPI HTTPUtilities implementation. * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - String getHTTPUtilitiesImplementation(); - - /** - * Gets the master key. This password is used to encrypt/decrypt other files or types - * of data that need to be protected by your application. - * - * @return the current master key + */ + @Deprecated + String getHTTPUtilitiesImplementation(); + + /** + * Gets the master key. This password is used to encrypt/decrypt other files or types + * of data that need to be protected by your application. + * + * @return the current master key * @deprecated Use SecurityConfiguration.getByteArrayProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - byte[] getMasterKey(); + */ + @Deprecated + byte[] getMasterKey(); - /** + /** * Retrieves the upload directory as specified in the ESAPI.properties file. * @return the upload directory */ File getUploadDirectory(); - + /** * Retrieves the temp directory to use when uploading files, as specified in ESAPI.properties. * @return the temp directory */ File getUploadTempDirectory(); - /** - * Gets the key length to use in cryptographic operations declared in the ESAPI properties file. + /** + * Gets the key length to use in cryptographic operations declared in the ESAPI properties file. * Note that this corresponds to the ESAPI property Encryptor.EncryptionKeyLength which is * considered the default key size that ESAPI will use for symmetric * ciphers supporting multiple key sizes. (Note that there is also an Encryptor.MinEncryptionKeyLength, * which is the minimum key size (in bits) that ESAPI will support * for encryption. (There is no miminimum for decryption.) - * - * @return the key length (in bits) + * + * @return the key length (in bits) * @deprecated Use SecurityConfiguration.getIntProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated + */ + @Deprecated int getEncryptionKeyLength(); - /** - * Gets the master salt that is used to salt stored password hashes and any other location - * where a salt is needed. - * - * @return the current master salt + /** + * Gets the master salt that is used to salt stored password hashes and any other location + * where a salt is needed. + * + * @return the current master salt * @deprecated Use SecurityConfiguration.getByteArrayProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - byte[] getMasterSalt(); - - /** - * Gets the allowed executables to run with the Executor. - * - * @return a list of the current allowed file extensions - */ - List getAllowedExecutables(); - - /** - * Gets the allowed file extensions for files that are uploaded to this application. - * - * @return a list of the current allowed file extensions - */ - List getAllowedFileExtensions(); - - /** - * Gets the maximum allowed file upload size. - * - * @return the current allowed file upload size + */ + @Deprecated + byte[] getMasterSalt(); + + /** + * Gets the allowed executables to run with the Executor. + * + * @return a list of the current allowed file extensions + */ + List getAllowedExecutables(); + + /** + * Gets the allowed file extensions for files that are uploaded to this application. + * + * @return a list of the current allowed file extensions + */ + List getAllowedFileExtensions(); + + /** + * Gets the maximum allowed file upload size. + * + * @return the current allowed file upload size * @deprecated Use SecurityConfiguration.getIntProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - int getAllowedFileUploadSize(); - - /** - * Gets the name of the password parameter used during user authentication. - * - * @return the name of the password parameter + */ + @Deprecated + int getAllowedFileUploadSize(); + + /** + * Gets the name of the password parameter used during user authentication. + * + * @return the name of the password parameter * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - String getPasswordParameterName(); - - /** - * Gets the name of the username parameter used during user authentication. - * - * @return the name of the username parameter + */ + @Deprecated + String getPasswordParameterName(); + + /** + * Gets the name of the username parameter used during user authentication. + * + * @return the name of the username parameter * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - String getUsernameParameterName(); - - /** - * Gets the encryption algorithm used by ESAPI to protect data. This is - * mostly used for compatibility with ESAPI 1.4; ESAPI 2.0 prefers to - * use "cipher transformation" since it supports multiple cipher modes - * and padding schemes. - * - * @return the current encryption algorithm + */ + @Deprecated + String getUsernameParameterName(); + + /** + * Gets the encryption algorithm used by ESAPI to protect data. This is + * mostly used for compatibility with ESAPI 1.4; ESAPI 2.0 prefers to + * use "cipher transformation" since it supports multiple cipher modes + * and padding schemes. + * + * @return the current encryption algorithm * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - String getEncryptionAlgorithm(); - - /** - * Retrieve the cipher transformation. In general, the cipher transformation - * is a specification of cipher algorithm, cipher mode, and padding scheme - * and in general, is a {@code String} that takes the following form: - *

    -	 * 		cipher_alg/cipher_mode[bits]/padding_scheme
    -	 * 
    - * where cipher_alg is the JCE cipher algorithm (e.g., "DESede"), - * cipher_mode is the cipher mode (e.g., "CBC", "CFB", "CTR", etc.), - * and padding_scheme is the cipher padding scheme (e.g., "NONE" for - * no padding, "PKCS5Padding" for PKCS#5 padding, etc.) and where - * [bits] is an optional bit size that applies to certain cipher - * modes such as {@code CFB} and {@code OFB}. Using modes such as CFB and - * OFB, block ciphers can encrypt data in units smaller than the cipher's - * actual block size. When requesting such a mode, you may optionally - * specify the number of bits to be processed at a time. This generally must - * be an integral multiple of 8-bits so that it can specify a whole number - * of octets. - *

    - * Examples are: - *

    -	 * 		"AES/ECB/NoPadding"		// Default for ESAPI Java 1.4 (insecure)
    -	 * 		"AES/CBC/PKCS5Padding"	// Default for ESAPI Java 2.0
    -	 * 		"DESede/OFB32/PKCS5Padding"
    -	 * 
    - * NOTE: Occasionally, in cryptographic literature, you may also - * see the key size (in bits) specified after the cipher algorithm in the - * cipher transformation. Generally, this is done to account for cipher - * algorithms that have variable key sizes. The Blowfish cipher for example - * supports key sizes from 32 to 448 bits. So for Blowfish, you might see - * a cipher transformation something like this: - *
    -	 * 		"Blowfish-192/CFB8/PKCS5Padding"
    -	 * 
    - * in the cryptographic literature. It should be noted that the Java - * Cryptography Extensions (JCE) do not generally support this (at least - * not the reference JCE implementation of "SunJCE"), and therefore it - * should be avoided. - * @return The cipher transformation. + */ + @Deprecated + String getEncryptionAlgorithm(); + + /** + * Retrieve the cipher transformation. In general, the cipher transformation + * is a specification of cipher algorithm, cipher mode, and padding scheme + * and in general, is a {@code String} that takes the following form: + *
    +     *         cipher_alg/cipher_mode[bits]/padding_scheme
    +     * 
    + * where cipher_alg is the JCE cipher algorithm (e.g., "DESede"), + * cipher_mode is the cipher mode (e.g., "CBC", "CFB", "CTR", etc.), + * and padding_scheme is the cipher padding scheme (e.g., "NONE" for + * no padding, "PKCS5Padding" for PKCS#5 padding, etc.) and where + * [bits] is an optional bit size that applies to certain cipher + * modes such as {@code CFB} and {@code OFB}. Using modes such as CFB and + * OFB, block ciphers can encrypt data in units smaller than the cipher's + * actual block size. When requesting such a mode, you may optionally + * specify the number of bits to be processed at a time. This generally must + * be an integral multiple of 8-bits so that it can specify a whole number + * of octets. + *

    + * Examples are: + *

    +     *         "AES/ECB/NoPadding"        // Default for ESAPI Java 1.4 (insecure)
    +     *         "AES/CBC/PKCS5Padding"    // Default for ESAPI Java 2.0
    +     *         "DESede/OFB32/PKCS5Padding"
    +     * 
    + * NOTE: Occasionally, in cryptographic literature, you may also + * see the key size (in bits) specified after the cipher algorithm in the + * cipher transformation. Generally, this is done to account for cipher + * algorithms that have variable key sizes. The Blowfish cipher for example + * supports key sizes from 32 to 448 bits. So for Blowfish, you might see + * a cipher transformation something like this: + *
    +     *         "Blowfish-192/CFB8/PKCS5Padding"
    +     * 
    + * in the cryptographic literature. It should be noted that the Java + * Cryptography Extensions (JCE) do not generally support this (at least + * not the reference JCE implementation of "SunJCE"), and therefore it + * should be avoided. + * @return The cipher transformation. * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated + */ + @Deprecated String getCipherTransformation(); /** @@ -300,21 +300,21 @@ public interface SecurityConfiguration extends EsapiPropertyLoader { * you may normally want to use AES/CBC/PKCS5Padding, but have some legacy * encryption where you have ciphertext that was encrypted using 3DES. * - * @param cipherXform The new cipher transformation. See - * {@link #getCipherTransformation} for format. If - * {@code null} is passed as the parameter, the cipher - * transformation will be set to the the default taken - * from the property {@code Encryptor.CipherTransformation} - * in the {@code ESAPI.properties} file. BEWARE: - * there is NO sanity checking here (other than - * the empty string, and then, only if Java assertions are - * enabled), so if you set this wrong, you will not get - * any errors until you later try to use it to encrypt - * or decrypt data. - * @return The previous cipher transformation is returned for convenience, - * with the assumption that you may wish to restore it once you have - * completed the encryption / decryption with the new cipher - * transformation. + * @param cipherXform The new cipher transformation. See + * {@link #getCipherTransformation} for format. If + * {@code null} is passed as the parameter, the cipher + * transformation will be set to the the default taken + * from the property {@code Encryptor.CipherTransformation} + * in the {@code ESAPI.properties} file. BEWARE: + * there is NO sanity checking here (other than + * the empty string, and then, only if Java assertions are + * enabled), so if you set this wrong, you will not get + * any errors until you later try to use it to encrypt + * or decrypt data. + * @return The previous cipher transformation is returned for convenience, + * with the assumption that you may wish to restore it once you have + * completed the encryption / decryption with the new cipher + * transformation. * @deprecated To be replaced by new class in ESAPI 2.1, but here if you need it * until then. Details of replacement forthcoming to ESAPI-Dev * list. Most likely to be replaced by a new CTOR for @@ -340,12 +340,12 @@ public interface SecurityConfiguration extends EsapiPropertyLoader { * @see org.owasp.esapi.crypto.SecurityProviderLoader * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. */ - @Deprecated + @Deprecated String getPreferredJCEProvider(); // TODO - DISCUSS: Where should this web page (below) go? Maybe with the Javadoc? But where? -// Think it makes more sense as part of the release notes, but OTOH, I -// really don't want to rewrite this as a Wiki page either. +// Think it makes more sense as part of the release notes, but OTOH, I +// really don't want to rewrite this as a Wiki page either. /** * Determines whether the {@code CipherText} should be used with a Message * Authentication Code (MAC). Generally this makes for a more robust cryptographic @@ -356,10 +356,10 @@ public interface SecurityConfiguration extends EsapiPropertyLoader { * * "Why Is OWASP Changing ESAPI Encryption?". *

    - * @return {@code true} if a you want a MAC to be used, otherwise {@code false}. + * @return {@code true} if a you want a MAC to be used, otherwise {@code false}. * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead. */ - @Deprecated + @Deprecated boolean useMACforCipherText(); /** @@ -373,11 +373,11 @@ public interface SecurityConfiguration extends EsapiPropertyLoader { * Controlled by the property {@code Encryptor.PlainText.overwrite} in * the {@code ESAPI.properties} file. *

    - * @return True if it is OK to overwrite the {@code PlainText} objects - * after encrypting, false otherwise. + * @return True if it is OK to overwrite the {@code PlainText} objects + * after encrypting, false otherwise. * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead. */ - @Deprecated + @Deprecated boolean overwritePlainText(); /** @@ -402,7 +402,7 @@ public interface SecurityConfiguration extends EsapiPropertyLoader { * This method will be removed in a future release as it is now moot since * it can only legitimately have the single value of "random". */ - @Deprecated + @Deprecated String getIVType(); /** @@ -441,185 +441,185 @@ public interface SecurityConfiguration extends EsapiPropertyLoader { */ List getAdditionalAllowedCipherModes(); - /** - * Gets the hashing algorithm used by ESAPI to hash data. - * - * @return the current hashing algorithm + /** + * Gets the hashing algorithm used by ESAPI to hash data. + * + * @return the current hashing algorithm * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - String getHashAlgorithm(); - - /** - * Gets the hash iterations used by ESAPI to hash data. - * - * @return the current hashing algorithm + */ + @Deprecated + String getHashAlgorithm(); + + /** + * Gets the hash iterations used by ESAPI to hash data. + * + * @return the current hashing algorithm * @deprecated Use SecurityConfiguration.getIntProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - int getHashIterations(); - - /** - * Retrieve the Pseudo Random Function (PRF) used by the ESAPI - * Key Derivation Function (KDF). - * - * @return The KDF PRF algorithm name. + */ + @Deprecated + int getHashIterations(); + + /** + * Retrieve the Pseudo Random Function (PRF) used by the ESAPI + * Key Derivation Function (KDF). + * + * @return The KDF PRF algorithm name. * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - String getKDFPseudoRandomFunction(); - - /** - * Gets the character encoding scheme supported by this application. This is used to set the - * character encoding scheme on requests and responses when setCharacterEncoding() is called - * on SafeRequests and SafeResponses. This scheme is also used for encoding/decoding URLs - * and any other place where the current encoding scheme needs to be known. - *

    - * Note: This does not get the configured response content type. That is accessed by calling - * getResponseContentType(). - * - * @return the current character encoding scheme + */ + @Deprecated + String getKDFPseudoRandomFunction(); + + /** + * Gets the character encoding scheme supported by this application. This is used to set the + * character encoding scheme on requests and responses when setCharacterEncoding() is called + * on SafeRequests and SafeResponses. This scheme is also used for encoding/decoding URLs + * and any other place where the current encoding scheme needs to be known. + *

    + * Note: This does not get the configured response content type. That is accessed by calling + * getResponseContentType(). + * + * @return the current character encoding scheme * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - String getCharacterEncoding(); - - /** - * Return true if multiple encoding is allowed - * - * @return whether multiple encoding is allowed when canonicalizing data + */ + @Deprecated + String getCharacterEncoding(); + + /** + * Return true if multiple encoding is allowed + * + * @return whether multiple encoding is allowed when canonicalizing data * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - boolean getAllowMultipleEncoding(); - - /** - * Return true if mixed encoding is allowed - * - * @return whether mixed encoding is allowed when canonicalizing data + */ + @Deprecated + boolean getAllowMultipleEncoding(); + + /** + * Return true if mixed encoding is allowed + * + * @return whether mixed encoding is allowed when canonicalizing data * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - boolean getAllowMixedEncoding(); - - /** - * Returns the List of Codecs to use when canonicalizing data - * - * @return the codec list - */ - List getDefaultCanonicalizationCodecs(); - - /** - * Gets the digital signature algorithm used by ESAPI to generate and verify signatures. - * - * @return the current digital signature algorithm + */ + @Deprecated + boolean getAllowMixedEncoding(); + + /** + * Returns the List of Codecs to use when canonicalizing data + * + * @return the codec list + */ + List getDefaultCanonicalizationCodecs(); + + /** + * Gets the digital signature algorithm used by ESAPI to generate and verify signatures. + * + * @return the current digital signature algorithm * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - String getDigitalSignatureAlgorithm(); - - /** - * Gets the digital signature key length used by ESAPI to generate and verify signatures. - * - * @return the current digital signature key length + */ + @Deprecated + String getDigitalSignatureAlgorithm(); + + /** + * Gets the digital signature key length used by ESAPI to generate and verify signatures. + * + * @return the current digital signature key length * @deprecated Use SecurityConfiguration.getIntProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - int getDigitalSignatureKeyLength(); - - /** - * Gets the random number generation algorithm used to generate random numbers where needed. - * - * @return the current random number generation algorithm + */ + @Deprecated + int getDigitalSignatureKeyLength(); + + /** + * Gets the random number generation algorithm used to generate random numbers where needed. + * + * @return the current random number generation algorithm * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - String getRandomAlgorithm(); - - /** - * Gets the number of login attempts allowed before the user's account is locked. If this - * many failures are detected within the alloted time period, the user's account will be locked. - * - * @return the number of failed login attempts that cause an account to be locked + */ + @Deprecated + String getRandomAlgorithm(); + + /** + * Gets the number of login attempts allowed before the user's account is locked. If this + * many failures are detected within the alloted time period, the user's account will be locked. + * + * @return the number of failed login attempts that cause an account to be locked * @deprecated Use SecurityConfiguration.getIntProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - int getAllowedLoginAttempts(); - - /** - * Gets the maximum number of old password hashes that should be retained. These hashes can - * be used to ensure that the user doesn't reuse the specified number of previous passwords - * when they change their password. - * - * @return the number of old hashed passwords to retain + */ + @Deprecated + int getAllowedLoginAttempts(); + + /** + * Gets the maximum number of old password hashes that should be retained. These hashes can + * be used to ensure that the user doesn't reuse the specified number of previous passwords + * when they change their password. + * + * @return the number of old hashed passwords to retain * @deprecated Use SecurityConfiguration.getIntProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - int getMaxOldPasswordHashes(); - - /** - * Allows for complete disabling of all intrusion detection mechanisms - * - * @return true if intrusion detection should be disabled + */ + @Deprecated + int getMaxOldPasswordHashes(); + + /** + * Allows for complete disabling of all intrusion detection mechanisms + * + * @return true if intrusion detection should be disabled * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - boolean getDisableIntrusionDetection(); - - /** - * Gets the intrusion detection quota for the specified event. - * - * @param eventName the name of the event whose quota is desired - * - * @return the Quota that has been configured for the specified type of event - */ - Threshold getQuota(String eventName); - - /** - * Gets a file from the resource directory + */ + @Deprecated + boolean getDisableIntrusionDetection(); + + /** + * Gets the intrusion detection quota for the specified event. + * + * @param eventName the name of the event whose quota is desired + * + * @return the Quota that has been configured for the specified type of event + */ + Threshold getQuota(String eventName); + + /** + * Gets a file from the resource directory * * @param filename The file name resource. * @return A {@code File} object representing the specified file name or null if not found. */ File getResourceFile( String filename ); - /** - * Returns true if session cookies are required to have HttpOnly flag set. + /** + * Returns true if session cookies are required to have HttpOnly flag set. * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead. */ - @Deprecated + @Deprecated boolean getForceHttpOnlySession() ; - /** - * Returns true if session cookies are required to have Secure flag set. + /** + * Returns true if session cookies are required to have Secure flag set. * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead. */ - @Deprecated + @Deprecated boolean getForceSecureSession() ; - /** - * Returns true if new cookies are required to have HttpOnly flag set. + /** + * Returns true if new cookies are required to have HttpOnly flag set. * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead. */ - @Deprecated + @Deprecated boolean getForceHttpOnlyCookies() ; - /** - * Returns true if new cookies are required to have Secure flag set. + /** + * Returns true if new cookies are required to have Secure flag set. * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead. */ - @Deprecated + @Deprecated boolean getForceSecureCookies() ; - /** - * Returns the maximum allowable HTTP header size. + /** + * Returns the maximum allowable HTTP header size. * @deprecated Use SecurityConfiguration.getIntProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - int getMaxHttpHeaderSize() ; + */ + @Deprecated + int getMaxHttpHeaderSize() ; - /** - * Gets an InputStream to a file in the resource directory + /** + * Gets an InputStream to a file in the resource directory * * @param filename A file name in the resource directory. * @return An {@code InputStream} to the specified file name in the resource directory. @@ -627,142 +627,142 @@ public interface SecurityConfiguration extends EsapiPropertyLoader { */ InputStream getResourceStream( String filename ) throws IOException; - /** - * Sets the ESAPI resource directory. - * - * @param dir The location of the resource directory. - */ - void setResourceDirectory(String dir); - - /** - * Gets the content type for responses used when setSafeContentType() is called. - *

    - * Note: This does not get the configured character encoding scheme. That is accessed by calling - * getCharacterEncoding(). - * - * @return The current content-type set for responses. + /** + * Sets the ESAPI resource directory. + * + * @param dir The location of the resource directory. + */ + void setResourceDirectory(String dir); + + /** + * Gets the content type for responses used when setSafeContentType() is called. + *

    + * Note: This does not get the configured character encoding scheme. That is accessed by calling + * getCharacterEncoding(). + * + * @return The current content-type set for responses. * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - String getResponseContentType(); - - /** - * This method returns the configured name of the session identifier, - * likely "JSESSIONID" though this can be overridden. - * - * @return The name of the session identifier, like "JSESSIONID" + */ + @Deprecated + String getResponseContentType(); + + /** + * This method returns the configured name of the session identifier, + * likely "JSESSIONID" though this can be overridden. + * + * @return The name of the session identifier, like "JSESSIONID" * @deprecated Use SecurityConfiguration.getStringProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - String getHttpSessionIdName(); - - /** - * Gets the length of the time to live window for remember me tokens (in milliseconds). - * - * @return The time to live length for generated "remember me" tokens. - */ + */ + @Deprecated + String getHttpSessionIdName(); + + /** + * Gets the length of the time to live window for remember me tokens (in milliseconds). + * + * @return The time to live length for generated "remember me" tokens. + */ // OPEN ISSUE: Can we replace w/ SecurityConfiguration.getIntProp("appropriate_esapi_prop_name") instead? - long getRememberTokenDuration(); - - - /** - * Gets the idle timeout length for sessions (in milliseconds). This is the amount of time that a session - * can live before it expires due to lack of activity. Applications or frameworks could provide a reauthenticate - * function that enables a session to continue after reauthentication. - * - * @return The session idle timeout length. + long getRememberTokenDuration(); + + + /** + * Gets the idle timeout length for sessions (in milliseconds). This is the amount of time that a session + * can live before it expires due to lack of activity. Applications or frameworks could provide a reauthenticate + * function that enables a session to continue after reauthentication. + * + * @return The session idle timeout length. * @deprecated Use SecurityConfiguration.getIntProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - int getSessionIdleTimeoutLength(); - - /** - * Gets the absolute timeout length for sessions (in milliseconds). This is the amount of time that a session - * can live before it expires regardless of the amount of user activity. Applications or frameworks could - * provide a reauthenticate function that enables a session to continue after reauthentication. - * - * @return The session absolute timeout length. + */ + @Deprecated + int getSessionIdleTimeoutLength(); + + /** + * Gets the absolute timeout length for sessions (in milliseconds). This is the amount of time that a session + * can live before it expires regardless of the amount of user activity. Applications or frameworks could + * provide a reauthenticate function that enables a session to continue after reauthentication. + * + * @return The session absolute timeout length. * @deprecated Use SecurityConfiguration.getIntProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - int getSessionAbsoluteTimeoutLength(); - - - /** - * Returns whether HTML entity encoding should be applied to log entries. - * - * @return True if log entries are to be HTML Entity encoded. False otherwise. + */ + @Deprecated + int getSessionAbsoluteTimeoutLength(); + + + /** + * Returns whether HTML entity encoding should be applied to log entries. + * + * @return True if log entries are to be HTML Entity encoded. False otherwise. * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - boolean getLogEncodingRequired(); - - /** - * Returns whether ESAPI should log the application name. This might be clutter in some - * single-server/single-app environments. - * - * @return True if ESAPI should log the application name, False otherwise + */ + @Deprecated + boolean getLogEncodingRequired(); + + /** + * Returns whether ESAPI should log the application name. This might be clutter in some + * single-server/single-app environments. + * + * @return True if ESAPI should log the application name, False otherwise * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - boolean getLogApplicationName(); - - /** - * Returns whether ESAPI should log the server IP. This might be clutter in some - * single-server environments. - * - * @return True if ESAPI should log the server IP and port, False otherwise + */ + @Deprecated + boolean getLogApplicationName(); + + /** + * Returns whether ESAPI should log the server IP. This might be clutter in some + * single-server environments. + * + * @return True if ESAPI should log the server IP and port, False otherwise * @deprecated Use SecurityConfiguration.getBooleanProp("appropriate_esapi_prop_name") instead. - */ - @Deprecated - boolean getLogServerIP(); - - /** - * Models a simple threshold as a count and an interval, along with a set of actions to take if - * the threshold is exceeded. These thresholds are used to define when the accumulation of a particular event - * has met a set number within the specified time period. Once a threshold value has been met, various - * actions can be taken at that point. - */ - class Threshold { - - /** The name of this threshold. */ - public String name = null; - - /** The count at which this threshold is triggered. */ - public int count = 0; - - /** - * The time frame within which 'count' number of actions has to be detected in order to - * trigger this threshold. - */ - public long interval = 0; - - /** - * The list of actions to take if the threshold is met. It is expected that this is a list of Strings, but - * your implementation could have this be a list of any type of 'actions' you wish to define. - */ - public List actions = null; - - /** - * Constructs a threshold that is composed of its name, its threshold count, the time window for - * the threshold, and the actions to take if the threshold is triggered. - * - * @param name The name of this threshold. - * @param count The count at which this threshold is triggered. - * @param interval The time frame within which 'count' number of actions has to be detected in order to - * trigger this threshold. - * @param actions The list of actions to take if the threshold is met. - */ - public Threshold(String name, int count, long interval, List actions) { - this.name = name; - this.count = count; - this.interval = interval; - this.actions = actions; - } - } - - /** - * Returns the default working directory for executing native processes with Runtime.exec(). - */ - File getWorkingDirectory(); + */ + @Deprecated + boolean getLogServerIP(); + + /** + * Models a simple threshold as a count and an interval, along with a set of actions to take if + * the threshold is exceeded. These thresholds are used to define when the accumulation of a particular event + * has met a set number within the specified time period. Once a threshold value has been met, various + * actions can be taken at that point. + */ + class Threshold { + + /** The name of this threshold. */ + public String name = null; + + /** The count at which this threshold is triggered. */ + public int count = 0; + + /** + * The time frame within which 'count' number of actions has to be detected in order to + * trigger this threshold. + */ + public long interval = 0; + + /** + * The list of actions to take if the threshold is met. It is expected that this is a list of Strings, but + * your implementation could have this be a list of any type of 'actions' you wish to define. + */ + public List actions = null; + + /** + * Constructs a threshold that is composed of its name, its threshold count, the time window for + * the threshold, and the actions to take if the threshold is triggered. + * + * @param name The name of this threshold. + * @param count The count at which this threshold is triggered. + * @param interval The time frame within which 'count' number of actions has to be detected in order to + * trigger this threshold. + * @param actions The list of actions to take if the threshold is met. + */ + public Threshold(String name, int count, long interval, List actions) { + this.name = name; + this.count = count; + this.interval = interval; + this.actions = actions; + } + } + + /** + * Returns the default working directory for executing native processes with Runtime.exec(). + */ + File getWorkingDirectory(); } diff --git a/src/main/java/org/owasp/esapi/StringUtilities.java b/src/main/java/org/owasp/esapi/StringUtilities.java index 634287ad1..19a29f7c9 100644 --- a/src/main/java/org/owasp/esapi/StringUtilities.java +++ b/src/main/java/org/owasp/esapi/StringUtilities.java @@ -27,31 +27,31 @@ */ public class StringUtilities { - private static final Pattern p = Pattern.compile( "\\s"); - public static String replaceLinearWhiteSpace( String input ) { - return p.matcher(input).replaceAll( " " ); - } - - /** - * Removes all unprintable characters from a string - * and replaces with a space. - * @param input - * @return the stripped value - */ - public static String stripControls( String input ) { - StringBuilder sb = new StringBuilder(); - for ( int i=0; i 0x20 && c < 0x7f ) { - sb.append( c ); - } else { - sb.append( ' ' ); - } - } - return sb.toString(); - } - - + private static final Pattern p = Pattern.compile( "\\s"); + public static String replaceLinearWhiteSpace( String input ) { + return p.matcher(input).replaceAll( " " ); + } + + /** + * Removes all unprintable characters from a string + * and replaces with a space. + * @param input + * @return the stripped value + */ + public static String stripControls( String input ) { + StringBuilder sb = new StringBuilder(); + for ( int i=0; i 0x20 && c < 0x7f ) { + sb.append( c ); + } else { + sb.append( ' ' ); + } + } + return sb.toString(); + } + + /** * Union multiple character arrays. * @@ -59,14 +59,14 @@ public static String stripControls( String input ) { * @return the union of the char[]s */ public static char[] union(char[]... list) { - StringBuilder sb = new StringBuilder(); - - for (char[] characters : list) { - for ( char c : characters ) { - if ( !contains( sb, c ) ) - sb.append( c ); - } - } + StringBuilder sb = new StringBuilder(); + + for (char[] characters : list) { + for ( char c : characters ) { + if ( !contains( sb, c ) ) + sb.append( c ); + } + } char[] toReturn = new char[sb.length()]; sb.getChars(0, sb.length(), toReturn, 0); @@ -75,11 +75,11 @@ public static char[] union(char[]... list) { } - /** + /** * Returns true if the character is contained in the provided StringBuilder. - * @param input The input - * @param c The character to check for to see if {@code input} contains. - * @return True if the specified character is contained; false otherwise. + * @param input The input + * @param c The character to check for to see if {@code input} contains. + * @return True if the specified character is contained; false otherwise. */ public static boolean contains(StringBuilder input, char c) { for (int i = 0; i < input.length(); i++) { @@ -171,24 +171,24 @@ public static int getLevenshteinDistance (String s, String t) { * trimming of leading and trailing whitespace). Usually used with * assertions, as in *
    -     * 		assert StringUtils.notNullOrEmpty(cipherXform, true) :
    -     * 								"Cipher transformation may not be null or empty!";
    +     *         assert StringUtils.notNullOrEmpty(cipherXform, true) :
    +     *                                 "Cipher transformation may not be null or empty!";
          * 
    * or an equivalent runtime check that throws an {@code IllegalArgumentException}. * - * @param str The {@code String} to be checked. - * @param trim If {@code true}, the string is first trimmed before checking - * to see if it is empty, otherwise it is not. - * @return True if the string is null or empty (after possible - * trimming); otherwise false. + * @param str The {@code String} to be checked. + * @param trim If {@code true}, the string is first trimmed before checking + * to see if it is empty, otherwise it is not. + * @return True if the string is null or empty (after possible + * trimming); otherwise false. * @since 2.0 */ public static boolean notNullOrEmpty(String str, boolean trim) { - if ( trim ) { - return !( str == null || str.trim().equals("") ); - } else { - return !( str == null || str.equals("") ); - } + if ( trim ) { + return !( str == null || str.trim().equals("") ); + } else { + return !( str == null || str.equals("") ); + } } /** diff --git a/src/main/java/org/owasp/esapi/User.java b/src/main/java/org/owasp/esapi/User.java index 480e97135..8e46a97e2 100644 --- a/src/main/java/org/owasp/esapi/User.java +++ b/src/main/java/org/owasp/esapi/User.java @@ -41,24 +41,24 @@ */ public interface User extends Principal, Serializable { - /** - * @return the locale - */ - Locale getLocale(); + /** + * @return the locale + */ + Locale getLocale(); - /** - * @param locale the locale to set - */ - void setLocale(Locale locale); + /** + * @param locale the locale to set + */ + void setLocale(Locale locale); /** * Adds a role to this user's account. * * @param role - * the role to add + * the role to add * * @throws AuthenticationException - * the authentication exception + * the authentication exception */ void addRole(String role) throws AuthenticationException; @@ -66,10 +66,10 @@ public interface User extends Principal, Serializable { * Adds a set of roles to this user's account. * * @param newRoles - * the new roles to add + * the new roles to add * * @throws AuthenticationException - * the authentication exception + * the authentication exception */ void addRoles(Set newRoles) throws AuthenticationException; @@ -78,14 +78,14 @@ public interface User extends Principal, Serializable { * passwords, and the strength of the new password. * * @param oldPassword - * the old password + * the old password * @param newPassword1 - * the new password + * the new password * @param newPassword2 - * the new password - used to verify that the new password was typed correctly + * the new password - used to verify that the new password was typed correctly * * @throws AuthenticationException - * if newPassword1 does not match newPassword2, if oldPassword does not match the stored old password, or if the new password does not meet complexity requirements + * if newPassword1 does not match newPassword2, if oldPassword does not match the stored old password, or if the new password does not meet complexity requirements * @throws EncryptionException */ void changePassword(String oldPassword, String newPassword1, String newPassword2) throws AuthenticationException, EncryptionException; @@ -146,14 +146,14 @@ public interface User extends Principal, Serializable { */ String getLastHostAddress(); - /** + /** * Returns the date of the last failed login time for a user. This date should be used in a message to users after a * successful login, to notify them of potential attack activity on their account. * * @return date of the last failed login * * @throws AuthenticationException - * the authentication exception + * the authentication exception */ Date getLastFailedLoginTime() throws AuthenticationException; @@ -190,7 +190,7 @@ public interface User extends Principal, Serializable { * Adds a session for this User. * * @param s - * The session to associate with this user. + * The session to associate with this user. */ void addSession( HttpSession s ); @@ -198,7 +198,7 @@ public interface User extends Principal, Serializable { * Removes a session for this User. * * @param s - * The session to remove from being associated with this user. + * The session to remove from being associated with this user. */ void removeSession( HttpSession s ); @@ -238,7 +238,7 @@ public interface User extends Principal, Serializable { * Checks if this user's account is assigned a particular role. * * @param role - * the role for which to check + * the role for which to check * * @return true, if role has been assigned to user */ @@ -272,7 +272,7 @@ public interface User extends Principal, Serializable { * * A session may timeout prior to ESAPI's configuration setting due to * the servlet container setting for session-timeout in web.xml. The - * following is an example of a web.xml session-timeout set for one hour. + * following is an example of a web.xml session-timeout set for one hour. * * * 60 @@ -292,9 +292,9 @@ public interface User extends Principal, Serializable { * Login with password. * * @param password - * the password + * the password * @throws AuthenticationException - * if login fails + * if login fails */ void loginWithPassword(String password) throws AuthenticationException; @@ -307,9 +307,9 @@ public interface User extends Principal, Serializable { * Removes a role from this user's account. * * @param role - * the role to remove + * the role to remove * @throws AuthenticationException - * the authentication exception + * the authentication exception */ void removeRole(String role) throws AuthenticationException; @@ -322,7 +322,7 @@ public interface User extends Principal, Serializable { * @return the new CSRF token * * @throws AuthenticationException - * the authentication exception + * the authentication exception */ String resetCSRFToken() throws AuthenticationException; @@ -338,16 +338,16 @@ public interface User extends Principal, Serializable { * * @param expirationTime the new expiration time */ - void setExpirationTime(Date expirationTime); + void setExpirationTime(Date expirationTime); - /** + /** * Sets the roles for this account. * * @param roles - * the new roles + * the new roles * * @throws AuthenticationException - * the authentication exception + * the authentication exception */ void setRoles(Set roles) throws AuthenticationException; @@ -363,80 +363,80 @@ public interface User extends Principal, Serializable { */ void unlock(); - /** - * Verify that the supplied password matches the password for this user. This method - * is typically used for "reauthentication" for the most sensitive functions, such - * as transactions, changing email address, and changing other account information. - * - * @param password - * the password that the user entered - * - * @return true, if the password passed in matches the account's password - * - * @throws EncryptionException - */ - boolean verifyPassword(String password) throws EncryptionException; - - /** - * Set the time of the last failed login for this user. - * - * @param lastFailedLoginTime the date and time when the user just failed to login correctly. - */ - void setLastFailedLoginTime(Date lastFailedLoginTime); - - /** - * Set the last remote host address used by this user. - * - * @param remoteHost The address of the user's current source host. - */ - void setLastHostAddress(String remoteHost) throws AuthenticationHostException; - - /** - * Set the time of the last successful login for this user. - * - * @param lastLoginTime the date and time when the user just successfully logged in. - */ - void setLastLoginTime(Date lastLoginTime); - - /** - * Set the time of the last password change for this user. - * - * @param lastPasswordChangeTime the date and time when the user just successfully changed his/her password. - */ - void setLastPasswordChangeTime(Date lastPasswordChangeTime); - - /** - * Returns the hashmap used to store security events for this user. Used by the - * IntrusionDetector. - */ - HashMap getEventMap(); - - - /** - * The ANONYMOUS user is used to represent an unidentified user. Since there is - * always a real user, the ANONYMOUS user is better than using null to represent - * this. - */ + /** + * Verify that the supplied password matches the password for this user. This method + * is typically used for "reauthentication" for the most sensitive functions, such + * as transactions, changing email address, and changing other account information. + * + * @param password + * the password that the user entered + * + * @return true, if the password passed in matches the account's password + * + * @throws EncryptionException + */ + boolean verifyPassword(String password) throws EncryptionException; + + /** + * Set the time of the last failed login for this user. + * + * @param lastFailedLoginTime the date and time when the user just failed to login correctly. + */ + void setLastFailedLoginTime(Date lastFailedLoginTime); + + /** + * Set the last remote host address used by this user. + * + * @param remoteHost The address of the user's current source host. + */ + void setLastHostAddress(String remoteHost) throws AuthenticationHostException; + + /** + * Set the time of the last successful login for this user. + * + * @param lastLoginTime the date and time when the user just successfully logged in. + */ + void setLastLoginTime(Date lastLoginTime); + + /** + * Set the time of the last password change for this user. + * + * @param lastPasswordChangeTime the date and time when the user just successfully changed his/her password. + */ + void setLastPasswordChangeTime(Date lastPasswordChangeTime); + + /** + * Returns the hashmap used to store security events for this user. Used by the + * IntrusionDetector. + */ + HashMap getEventMap(); + + + /** + * The ANONYMOUS user is used to represent an unidentified user. Since there is + * always a real user, the ANONYMOUS user is better than using null to represent + * this. + */ User ANONYMOUS = new User() { - private static final long serialVersionUID = -1850916950784965502L; + private static final long serialVersionUID = -1850916950784965502L; - private String csrfToken = ""; - private Set sessions = new HashSet(); - private Locale locale = null; - - /** + private String csrfToken = ""; + private Set sessions = new HashSet(); + private Locale locale = null; + + /** * {@inheritDoc} */ public void addRole(String role) throws AuthenticationException { - throw new RuntimeException("Invalid operation for the anonymous user"); + throw new RuntimeException("Invalid operation for the anonymous user"); } /** * {@inheritDoc} */ public void addRoles(Set newRoles) throws AuthenticationException { - throw new RuntimeException("Invalid operation for the anonymous user"); + throw new RuntimeException("Invalid operation for the anonymous user"); } /** @@ -445,107 +445,107 @@ public void addRoles(Set newRoles) throws AuthenticationException { public void changePassword(String oldPassword, String newPassword1, String newPassword2) throws AuthenticationException, EncryptionException { - throw new RuntimeException("Invalid operation for the anonymous user"); + throw new RuntimeException("Invalid operation for the anonymous user"); } /** * {@inheritDoc} */ public void disable() { - throw new RuntimeException("Invalid operation for the anonymous user"); + throw new RuntimeException("Invalid operation for the anonymous user"); } /** * {@inheritDoc} */ public void enable() { - throw new RuntimeException("Invalid operation for the anonymous user"); + throw new RuntimeException("Invalid operation for the anonymous user"); } /** * {@inheritDoc} */ public long getAccountId() { - return 0; + return 0; } /** * {@inheritDoc} */ public String getAccountName() { - return "Anonymous"; + return "Anonymous"; } - /** - * Alias method that is equivalent to getAccountName() - * - * @return the name of the current user's account + /** + * Alias method that is equivalent to getAccountName() + * + * @return the name of the current user's account */ public String getName() { - return getAccountName(); + return getAccountName(); } /** * {@inheritDoc} */ public String getCSRFToken() { - return csrfToken; + return csrfToken; } /** * {@inheritDoc} */ public Date getExpirationTime() { - return null; + return null; } /** * {@inheritDoc} */ public int getFailedLoginCount() { - return 0; + return 0; } /** * {@inheritDoc} */ public Date getLastFailedLoginTime() throws AuthenticationException { - return null; + return null; } /** * {@inheritDoc} */ public String getLastHostAddress() { - return "unknown"; + return "unknown"; } /** * {@inheritDoc} */ public Date getLastLoginTime() { - return null; + return null; } /** * {@inheritDoc} */ public Date getLastPasswordChangeTime() { - return null; + return null; } /** * {@inheritDoc} */ public Set getRoles() { - return new HashSet(); + return new HashSet(); } /** * {@inheritDoc} */ public String getScreenName() { - return "Anonymous"; + return "Anonymous"; } /** @@ -571,70 +571,70 @@ public Set getSessions() { * {@inheritDoc} */ public void incrementFailedLoginCount() { - throw new RuntimeException("Invalid operation for the anonymous user"); + throw new RuntimeException("Invalid operation for the anonymous user"); } /** * {@inheritDoc} */ public boolean isAnonymous() { - return true; + return true; } /** * {@inheritDoc} */ public boolean isEnabled() { - return false; + return false; } /** * {@inheritDoc} */ public boolean isExpired() { - return false; + return false; } /** * {@inheritDoc} */ public boolean isInRole(String role) { - return false; + return false; } /** * {@inheritDoc} */ public boolean isLocked() { - return false; + return false; } /** * {@inheritDoc} */ public boolean isLoggedIn() { - return false; + return false; } /** * {@inheritDoc} */ public boolean isSessionAbsoluteTimeout() { - return false; + return false; } /** * {@inheritDoc} */ public boolean isSessionTimeout() { - return false; + return false; } /** * {@inheritDoc} */ public void lock() { - throw new RuntimeException("Invalid operation for the anonymous user"); + throw new RuntimeException("Invalid operation for the anonymous user"); } /** @@ -642,119 +642,119 @@ public void lock() { */ public void loginWithPassword(String password) throws AuthenticationException { - throw new RuntimeException("Invalid operation for the anonymous user"); + throw new RuntimeException("Invalid operation for the anonymous user"); } /** * {@inheritDoc} */ public void logout() { - throw new RuntimeException("Invalid operation for the anonymous user"); + throw new RuntimeException("Invalid operation for the anonymous user"); } /** * {@inheritDoc} */ public void removeRole(String role) throws AuthenticationException { - throw new RuntimeException("Invalid operation for the anonymous user"); + throw new RuntimeException("Invalid operation for the anonymous user"); } /** * {@inheritDoc} */ public String resetCSRFToken() throws AuthenticationException { - csrfToken = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS); - return csrfToken; + csrfToken = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS); + return csrfToken; } /** * {@inheritDoc} */ public void setAccountName(String accountName) { - throw new RuntimeException("Invalid operation for the anonymous user"); + throw new RuntimeException("Invalid operation for the anonymous user"); } /** * {@inheritDoc} */ - public void setExpirationTime(Date expirationTime) { - throw new RuntimeException("Invalid operation for the anonymous user"); + public void setExpirationTime(Date expirationTime) { + throw new RuntimeException("Invalid operation for the anonymous user"); } - /** + /** * {@inheritDoc} */ public void setRoles(Set roles) throws AuthenticationException { - throw new RuntimeException("Invalid operation for the anonymous user"); + throw new RuntimeException("Invalid operation for the anonymous user"); } /** * {@inheritDoc} */ public void setScreenName(String screenName) { - throw new RuntimeException("Invalid operation for the anonymous user"); + throw new RuntimeException("Invalid operation for the anonymous user"); } /** * {@inheritDoc} */ public void unlock() { - throw new RuntimeException("Invalid operation for the anonymous user"); + throw new RuntimeException("Invalid operation for the anonymous user"); } /** * {@inheritDoc} */ public boolean verifyPassword(String password) throws EncryptionException { - throw new RuntimeException("Invalid operation for the anonymous user"); + throw new RuntimeException("Invalid operation for the anonymous user"); } /** * {@inheritDoc} */ public void setLastFailedLoginTime(Date lastFailedLoginTime) { - throw new RuntimeException("Invalid operation for the anonymous user"); + throw new RuntimeException("Invalid operation for the anonymous user"); } /** * {@inheritDoc} */ - public void setLastLoginTime(Date lastLoginTime) { - throw new RuntimeException("Invalid operation for the anonymous user"); - } + public void setLastLoginTime(Date lastLoginTime) { + throw new RuntimeException("Invalid operation for the anonymous user"); + } - /** + /** * {@inheritDoc} */ - public void setLastHostAddress(String remoteHost) { - throw new RuntimeException("Invalid operation for the anonymous user"); + public void setLastHostAddress(String remoteHost) { + throw new RuntimeException("Invalid operation for the anonymous user"); } - /** + /** * {@inheritDoc} */ public void setLastPasswordChangeTime(Date lastPasswordChangeTime) { - throw new RuntimeException("Invalid operation for the anonymous user"); + throw new RuntimeException("Invalid operation for the anonymous user"); } /** * {@inheritDoc} */ public HashMap getEventMap() { - throw new RuntimeException("Invalid operation for the anonymous user"); + throw new RuntimeException("Invalid operation for the anonymous user"); } /** - * @return the locale - */ - public Locale getLocale() { - return locale; - } - - /** - * @param locale the locale to set - */ - public void setLocale(Locale locale) { - this.locale = locale; - } + * @return the locale + */ + public Locale getLocale() { + return locale; + } + + /** + * @param locale the locale to set + */ + public void setLocale(Locale locale) { + this.locale = locale; + } }; } diff --git a/src/main/java/org/owasp/esapi/ValidationErrorList.java b/src/main/java/org/owasp/esapi/ValidationErrorList.java index 6479ff376..0837f0d32 100644 --- a/src/main/java/org/owasp/esapi/ValidationErrorList.java +++ b/src/main/java/org/owasp/esapi/ValidationErrorList.java @@ -49,7 +49,7 @@ * if (request.getAttribute(Constants.ERROR_LIST) != null) { * errors = (ValidationErrorList)request.getAttribute("ERROR_LIST"); * } - * return errors; + * return errors; * } * * @@ -77,61 +77,61 @@ */ public class ValidationErrorList { - /** - * Error list of ValidationException's - */ - private HashMap errorList = new HashMap(); + /** + * Error list of ValidationException's + */ + private HashMap errorList = new HashMap(); - /** - * Adds a new error to list with a unique named context. - * No action taken if either element is null. - * Existing contexts will be overwritten. - * - * @param context Unique named context for this {@code ValidationErrorList}. - * @param vex A {@code ValidationException}. - */ - public void addError(String context, ValidationException vex) { - if ( context == null ) throw new RuntimeException( "Context cannot be null: " + vex.getLogMessage(), vex ); - if ( vex == null ) throw new RuntimeException( "ValidationException cannot be null for context (" + context + ")" ); - if (getError(context) != null) throw new RuntimeException("Context (" + context + ") already exists, must be unique"); - errorList.put(context, vex); - } + /** + * Adds a new error to list with a unique named context. + * No action taken if either element is null. + * Existing contexts will be overwritten. + * + * @param context Unique named context for this {@code ValidationErrorList}. + * @param vex A {@code ValidationException}. + */ + public void addError(String context, ValidationException vex) { + if ( context == null ) throw new RuntimeException( "Context cannot be null: " + vex.getLogMessage(), vex ); + if ( vex == null ) throw new RuntimeException( "ValidationException cannot be null for context (" + context + ")" ); + if (getError(context) != null) throw new RuntimeException("Context (" + context + ") already exists, must be unique"); + errorList.put(context, vex); + } - /** - * Returns list of ValidationException, or empty list of no errors exist. - * - * @return List - */ - public List errors() { - return new ArrayList( errorList.values() ); - } + /** + * Returns list of ValidationException, or empty list of no errors exist. + * + * @return List + */ + public List errors() { + return new ArrayList( errorList.values() ); + } - /** - * Retrieves ValidationException for given context if one exists. - * - * @param context unique name for each error - * @return ValidationException or null for given context - */ - public ValidationException getError(String context) { - if (context == null) return null; - return errorList.get(context); - } + /** + * Retrieves ValidationException for given context if one exists. + * + * @param context unique name for each error + * @return ValidationException or null for given context + */ + public ValidationException getError(String context) { + if (context == null) return null; + return errorList.get(context); + } - /** - * Returns true if no error are present. - * - * @return boolean - */ - public boolean isEmpty() { - return errorList.isEmpty(); - } - - /** - * Returns the numbers of errors present. - * - * @return boolean - */ - public int size() { - return errorList.size(); - } + /** + * Returns true if no error are present. + * + * @return boolean + */ + public boolean isEmpty() { + return errorList.isEmpty(); + } + + /** + * Returns the numbers of errors present. + * + * @return boolean + */ + public int size() { + return errorList.size(); + } } diff --git a/src/main/java/org/owasp/esapi/ValidationRule.java b/src/main/java/org/owasp/esapi/ValidationRule.java index 9299ef8e3..985bb169c 100644 --- a/src/main/java/org/owasp/esapi/ValidationRule.java +++ b/src/main/java/org/owasp/esapi/ValidationRule.java @@ -6,16 +6,16 @@ public interface ValidationRule { - /** - * Parse the input, throw exceptions if validation fails - * - * @param context - * for logging - * @param input - * the value to be parsed - * @return a validated value - * @throws ValidationException - * if any validation rules fail, except if the + /** + * Parse the input, throw exceptions if validation fails + * + * @param context + * for logging + * @param input + * the value to be parsed + * @return a validated value + * @throws ValidationException + * if any validation rules fail, except if the * {@code ESAPI.properties}> property * "Validator.ValidationRule.getValid.ignore509Fix" is set to * {@code true}, which is the default behavior for ESAPI 2.x @@ -25,67 +25,67 @@ public interface ValidationRule { * for futher details. * * @see #getValid(String context, String input, ValidationErrorList errorList) - */ - Object getValid(String context, String input) - throws ValidationException; + */ + Object getValid(String context, String input) + throws ValidationException; - /** - * Whether or not a valid valid can be null. {@code getValid} will throw an - * Exception and {#code getSafe} will return the default value if flag is set to - * true - * - * @param flag - * whether or not null values are valid/safe - */ - void setAllowNull(boolean flag); + /** + * Whether or not a valid valid can be null. {@code getValid} will throw an + * Exception and {#code getSafe} will return the default value if flag is set to + * true + * + * @param flag + * whether or not null values are valid/safe + */ + void setAllowNull(boolean flag); - /** - * Programmatically supplied name for the validator - * @return a name, describing the validator - */ - String getTypeName(); + /** + * Programmatically supplied name for the validator + * @return a name, describing the validator + */ + String getTypeName(); - /** - * @param typeName a name, describing the validator - */ - void setTypeName(String typeName); + /** + * @param typeName a name, describing the validator + */ + void setTypeName(String typeName); - /** - * @param encoder the encoder to use - */ - void setEncoder(Encoder encoder); + /** + * @param encoder the encoder to use + */ + void setEncoder(Encoder encoder); - /** - * Check if the input is valid, throw an Exception otherwise - */ - void assertValid(String context, String input) - throws ValidationException; + /** + * Check if the input is valid, throw an Exception otherwise + */ + void assertValid(String context, String input) + throws ValidationException; - /** - * Get a validated value, add the errors to an existing error list - */ - Object getValid(String context, String input, - ValidationErrorList errorList) throws ValidationException; + /** + * Get a validated value, add the errors to an existing error list + */ + Object getValid(String context, String input, + ValidationErrorList errorList) throws ValidationException; - /** - * Try to call {@code getvalid}, then call a 'sanitize' method for sanitization (if one exists), + /** + * Try to call {@code getvalid}, then call a 'sanitize' method for sanitization (if one exists), * finally return a default value. - */ - Object getSafe(String context, String input); - - /** - * @return true if the input passes validation - */ - boolean isValid(String context, String input); + */ + Object getSafe(String context, String input); + + /** + * @return true if the input passes validation + */ + boolean isValid(String context, String input); - /** - * String the input of all chars contained in the list - */ - String whitelist(String input, char[] list); - - /** - * String the input of all chars contained in the list - */ - String whitelist(String input, Set list); + /** + * String the input of all chars contained in the list + */ + String whitelist(String input, char[] list); + + /** + * String the input of all chars contained in the list + */ + String whitelist(String input, Set list); } diff --git a/src/main/java/org/owasp/esapi/Validator.java b/src/main/java/org/owasp/esapi/Validator.java index e4ae1a670..1c3987746 100644 --- a/src/main/java/org/owasp/esapi/Validator.java +++ b/src/main/java/org/owasp/esapi/Validator.java @@ -48,679 +48,679 @@ */ public interface Validator { - /** - * Add a validation rule to the registry using the "type name" of the rule as the key. - */ - void addRule( ValidationRule rule ); - - /** - * Get a validation rule from the registry with the "type name" of the rule as the key. - */ - ValidationRule getRule( String name ); - - /** - * Calls isValidInput and returns true if no exceptions are thrown. - */ - boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull) throws IntrusionException; - - /** - * Calls isValidInput and returns true if no exceptions are thrown. - */ - boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Calls isValidInput and returns true if no exceptions are thrown. - */ - boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize) throws IntrusionException; - - /** - * Calls isValidInput and returns true if no exceptions are thrown. - */ - boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize, ValidationErrorList errorList) throws IntrusionException; - - /** - * Returns canonicalized and validated input as a String. Invalid input will generate a descriptive ValidationException, - * and input that is clearly an attack will generate a descriptive IntrusionException. - * - * @param context - * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. - * @param input - * The actual user input data to validate. - * @param type - * The regular expression name that maps to the actual regular expression from "ESAPI.properties". - * @param maxLength - * The maximum post-canonicalized String length allowed. - * @param allowNull - * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. - * - * @return The canonicalized user input. - * - * @throws ValidationException - * @throws IntrusionException - */ - String getValidInput(String context, String input, String type, int maxLength, boolean allowNull) throws ValidationException, IntrusionException; - - /** - * Returns validated input as a String with optional canonicalization. Invalid input will generate a descriptive ValidationException, - * and input that is clearly an attack will generate a descriptive IntrusionException. - * - * @param context - * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. - * @param input - * The actual user input data to validate. - * @param type - * The regular expression name that maps to the actual regular expression from "ESAPI.properties". - * @param maxLength - * The maximum post-canonicalized String length allowed. - * @param allowNull - * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. - * @param canonicalize - * If canonicalize is true then input will be canonicalized before validation - * - * @return The canonicalized user input. - * - * @throws ValidationException - * @throws IntrusionException - */ - String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize) throws ValidationException, IntrusionException; - - /** - * Calls getValidInput with the supplied errorList to capture ValidationExceptions - */ - String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Calls getValidInput with the supplied errorList to capture ValidationExceptions - */ - String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize, ValidationErrorList errorList) throws IntrusionException; - - /** - * Calls isValidDate and returns true if no exceptions are thrown. - */ - boolean isValidDate(String context, String input, DateFormat format, boolean allowNull) throws IntrusionException; - - /** - * Calls isValidDate and returns true if no exceptions are thrown. - */ - boolean isValidDate(String context, String input, DateFormat format, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Returns a valid date as a Date. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack - * will generate a descriptive IntrusionException. - * - * @param context - * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. - * @param input - * The actual user input data to validate. - * @param format - * Required formatting of date inputted. - * @param allowNull - * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. - * - * @return A valid date as a Date - * - * @throws ValidationException - * @throws IntrusionException - */ - Date getValidDate(String context, String input, DateFormat format, boolean allowNull) throws ValidationException, IntrusionException; - - /** - * Calls getValidDate with the supplied errorList to capture ValidationExceptions - */ - Date getValidDate(String context, String input, DateFormat format, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Calls getValidSafeHTML and returns true if no exceptions are thrown. - */ - boolean isValidSafeHTML(String context, String input, int maxLength, boolean allowNull) throws IntrusionException; - - /** - * Calls getValidSafeHTML and returns true if no exceptions are thrown. - */ - boolean isValidSafeHTML(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Returns canonicalized and validated "safe" HTML that does not contain unwanted scripts in the body, attributes, CSS, URLs, or anywhere else. - * Implementors should reference the OWASP AntiSamy project for ideas - * on how to do HTML validation in a whitelist way, as this is an extremely difficult problem. - * - * @param context - * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. - * @param input - * The actual user input data to validate. - * @param maxLength - * The maximum String length allowed. - * @param allowNull - * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. - * - * @return Valid safe HTML - * - * @throws ValidationException - * @throws IntrusionException - */ - String getValidSafeHTML(String context, String input, int maxLength, boolean allowNull) throws ValidationException, IntrusionException; - - /** - * Calls getValidSafeHTML with the supplied errorList to capture ValidationExceptions - */ - String getValidSafeHTML(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Calls getValidCreditCard and returns true if no exceptions are thrown. - */ - boolean isValidCreditCard(String context, String input, boolean allowNull) throws IntrusionException; - - /** - * Calls getValidCreditCard and returns true if no exceptions are thrown. - */ - boolean isValidCreditCard(String context, String input, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Returns a canonicalized and validated credit card number as a String. Invalid input - * will generate a descriptive ValidationException, and input that is clearly an attack - * will generate a descriptive IntrusionException. - * - * @param context - * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. - * @param input - * The actual user input data to validate. - * @param allowNull - * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. - * - * @return A valid credit card number - * - * @throws ValidationException - * @throws IntrusionException - */ - String getValidCreditCard(String context, String input, boolean allowNull) throws ValidationException, IntrusionException; - - /** - * Calls getValidCreditCard with the supplied errorList to capture ValidationExceptions - */ - String getValidCreditCard(String context, String input, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Calls getValidDirectoryPath and returns true if no exceptions are thrown. - */ - boolean isValidDirectoryPath(String context, String input, File parent, boolean allowNull) throws IntrusionException; - - /** - * Calls getValidDirectoryPath and returns true if no exceptions are thrown. - */ - boolean isValidDirectoryPath(String context, String input, File parent, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Returns a canonicalized and validated directory path as a String, provided that the input - * maps to an existing directory that is an existing subdirectory (at any level) of the specified parent. Invalid input - * will generate a descriptive ValidationException, and input that is clearly an attack - * will generate a descriptive IntrusionException. Instead of throwing a ValidationException - * on error, this variant will store the exception inside of the ValidationErrorList. - * - * @param context - * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. - * @param input - * The actual input data to validate. - * @param allowNull - * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. - * - * @return A valid directory path - * - * @throws ValidationException - * @throws IntrusionException - */ - String getValidDirectoryPath(String context, String input, File parent, boolean allowNull) throws ValidationException, IntrusionException; - - /** - * Calls getValidDirectoryPath with the supplied errorList to capture ValidationExceptions - */ - String getValidDirectoryPath(String context, String input, File parent, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Calls getValidFileName with the default list of allowedExtensions - */ - boolean isValidFileName(String context, String input, boolean allowNull) throws IntrusionException; - - /** - * Calls getValidFileName with the default list of allowedExtensions - */ - boolean isValidFileName(String context, String input, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Calls getValidFileName and returns true if no exceptions are thrown. - */ - boolean isValidFileName(String context, String input, List allowedExtensions, boolean allowNull) throws IntrusionException; - - /** - * Calls getValidFileName and returns true if no exceptions are thrown. - */ - boolean isValidFileName(String context, String input, List allowedExtensions, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Returns a canonicalized and validated file name as a String. Implementors should check for allowed file extensions here, as well as allowed file name characters, as declared in "ESAPI.properties". Invalid input - * will generate a descriptive ValidationException, and input that is clearly an attack - * will generate a descriptive IntrusionException. - * - * @param context - * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. + /** + * Add a validation rule to the registry using the "type name" of the rule as the key. + */ + void addRule( ValidationRule rule ); + + /** + * Get a validation rule from the registry with the "type name" of the rule as the key. + */ + ValidationRule getRule( String name ); + + /** + * Calls isValidInput and returns true if no exceptions are thrown. + */ + boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull) throws IntrusionException; + + /** + * Calls isValidInput and returns true if no exceptions are thrown. + */ + boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Calls isValidInput and returns true if no exceptions are thrown. + */ + boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize) throws IntrusionException; + + /** + * Calls isValidInput and returns true if no exceptions are thrown. + */ + boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize, ValidationErrorList errorList) throws IntrusionException; + + /** + * Returns canonicalized and validated input as a String. Invalid input will generate a descriptive ValidationException, + * and input that is clearly an attack will generate a descriptive IntrusionException. + * + * @param context + * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. + * @param input + * The actual user input data to validate. + * @param type + * The regular expression name that maps to the actual regular expression from "ESAPI.properties". + * @param maxLength + * The maximum post-canonicalized String length allowed. + * @param allowNull + * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. + * + * @return The canonicalized user input. + * + * @throws ValidationException + * @throws IntrusionException + */ + String getValidInput(String context, String input, String type, int maxLength, boolean allowNull) throws ValidationException, IntrusionException; + + /** + * Returns validated input as a String with optional canonicalization. Invalid input will generate a descriptive ValidationException, + * and input that is clearly an attack will generate a descriptive IntrusionException. + * + * @param context + * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. + * @param input + * The actual user input data to validate. + * @param type + * The regular expression name that maps to the actual regular expression from "ESAPI.properties". + * @param maxLength + * The maximum post-canonicalized String length allowed. + * @param allowNull + * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. + * @param canonicalize + * If canonicalize is true then input will be canonicalized before validation + * + * @return The canonicalized user input. + * + * @throws ValidationException + * @throws IntrusionException + */ + String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize) throws ValidationException, IntrusionException; + + /** + * Calls getValidInput with the supplied errorList to capture ValidationExceptions + */ + String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Calls getValidInput with the supplied errorList to capture ValidationExceptions + */ + String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize, ValidationErrorList errorList) throws IntrusionException; + + /** + * Calls isValidDate and returns true if no exceptions are thrown. + */ + boolean isValidDate(String context, String input, DateFormat format, boolean allowNull) throws IntrusionException; + + /** + * Calls isValidDate and returns true if no exceptions are thrown. + */ + boolean isValidDate(String context, String input, DateFormat format, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Returns a valid date as a Date. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack + * will generate a descriptive IntrusionException. + * + * @param context + * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. + * @param input + * The actual user input data to validate. + * @param format + * Required formatting of date inputted. + * @param allowNull + * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. + * + * @return A valid date as a Date + * + * @throws ValidationException + * @throws IntrusionException + */ + Date getValidDate(String context, String input, DateFormat format, boolean allowNull) throws ValidationException, IntrusionException; + + /** + * Calls getValidDate with the supplied errorList to capture ValidationExceptions + */ + Date getValidDate(String context, String input, DateFormat format, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Calls getValidSafeHTML and returns true if no exceptions are thrown. + */ + boolean isValidSafeHTML(String context, String input, int maxLength, boolean allowNull) throws IntrusionException; + + /** + * Calls getValidSafeHTML and returns true if no exceptions are thrown. + */ + boolean isValidSafeHTML(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Returns canonicalized and validated "safe" HTML that does not contain unwanted scripts in the body, attributes, CSS, URLs, or anywhere else. + * Implementors should reference the OWASP AntiSamy project for ideas + * on how to do HTML validation in a whitelist way, as this is an extremely difficult problem. + * + * @param context + * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. * @param input - * The actual input data to validate. + * The actual user input data to validate. + * @param maxLength + * The maximum String length allowed. * @param allowNull - * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. + * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. + * + * @return Valid safe HTML + * + * @throws ValidationException + * @throws IntrusionException + */ + String getValidSafeHTML(String context, String input, int maxLength, boolean allowNull) throws ValidationException, IntrusionException; + + /** + * Calls getValidSafeHTML with the supplied errorList to capture ValidationExceptions + */ + String getValidSafeHTML(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Calls getValidCreditCard and returns true if no exceptions are thrown. + */ + boolean isValidCreditCard(String context, String input, boolean allowNull) throws IntrusionException; + + /** + * Calls getValidCreditCard and returns true if no exceptions are thrown. + */ + boolean isValidCreditCard(String context, String input, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Returns a canonicalized and validated credit card number as a String. Invalid input + * will generate a descriptive ValidationException, and input that is clearly an attack + * will generate a descriptive IntrusionException. + * + * @param context + * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. + * @param input + * The actual user input data to validate. + * @param allowNull + * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. + * + * @return A valid credit card number + * + * @throws ValidationException + * @throws IntrusionException + */ + String getValidCreditCard(String context, String input, boolean allowNull) throws ValidationException, IntrusionException; + + /** + * Calls getValidCreditCard with the supplied errorList to capture ValidationExceptions + */ + String getValidCreditCard(String context, String input, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Calls getValidDirectoryPath and returns true if no exceptions are thrown. + */ + boolean isValidDirectoryPath(String context, String input, File parent, boolean allowNull) throws IntrusionException; + + /** + * Calls getValidDirectoryPath and returns true if no exceptions are thrown. + */ + boolean isValidDirectoryPath(String context, String input, File parent, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Returns a canonicalized and validated directory path as a String, provided that the input + * maps to an existing directory that is an existing subdirectory (at any level) of the specified parent. Invalid input + * will generate a descriptive ValidationException, and input that is clearly an attack + * will generate a descriptive IntrusionException. Instead of throwing a ValidationException + * on error, this variant will store the exception inside of the ValidationErrorList. + * + * @param context + * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. + * @param input + * The actual input data to validate. + * @param allowNull + * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. + * + * @return A valid directory path + * + * @throws ValidationException + * @throws IntrusionException + */ + String getValidDirectoryPath(String context, String input, File parent, boolean allowNull) throws ValidationException, IntrusionException; + + /** + * Calls getValidDirectoryPath with the supplied errorList to capture ValidationExceptions + */ + String getValidDirectoryPath(String context, String input, File parent, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Calls getValidFileName with the default list of allowedExtensions + */ + boolean isValidFileName(String context, String input, boolean allowNull) throws IntrusionException; + + /** + * Calls getValidFileName with the default list of allowedExtensions + */ + boolean isValidFileName(String context, String input, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Calls getValidFileName and returns true if no exceptions are thrown. + */ + boolean isValidFileName(String context, String input, List allowedExtensions, boolean allowNull) throws IntrusionException; + + /** + * Calls getValidFileName and returns true if no exceptions are thrown. + */ + boolean isValidFileName(String context, String input, List allowedExtensions, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Returns a canonicalized and validated file name as a String. Implementors should check for allowed file extensions here, as well as allowed file name characters, as declared in "ESAPI.properties". Invalid input + * will generate a descriptive ValidationException, and input that is clearly an attack + * will generate a descriptive IntrusionException. + * + * @param context + * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. + * @param input + * The actual input data to validate. + * @param allowNull + * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. * * @return A valid file name * * @throws ValidationException * @throws IntrusionException - */ - String getValidFileName(String context, String input, List allowedExtensions, boolean allowNull) throws ValidationException, IntrusionException; - - /** - * Calls getValidFileName with the supplied errorList to capture ValidationExceptions - */ - String getValidFileName(String context, String input, List allowedExtensions, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Calls getValidNumber and returns true if no exceptions are thrown. - */ - boolean isValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull) throws IntrusionException; - - /** - * Calls getValidNumber and returns true if no exceptions are thrown. - */ - boolean isValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Returns a validated number as a double within the range of minValue to maxValue. Invalid input - * will generate a descriptive ValidationException, and input that is clearly an attack - * will generate a descriptive IntrusionException. - * - * @param context - * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. + */ + String getValidFileName(String context, String input, List allowedExtensions, boolean allowNull) throws ValidationException, IntrusionException; + + /** + * Calls getValidFileName with the supplied errorList to capture ValidationExceptions + */ + String getValidFileName(String context, String input, List allowedExtensions, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Calls getValidNumber and returns true if no exceptions are thrown. + */ + boolean isValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull) throws IntrusionException; + + /** + * Calls getValidNumber and returns true if no exceptions are thrown. + */ + boolean isValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Returns a validated number as a double within the range of minValue to maxValue. Invalid input + * will generate a descriptive ValidationException, and input that is clearly an attack + * will generate a descriptive IntrusionException. + * + * @param context + * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. * @param input - * The actual input data to validate. + * The actual input data to validate. * @param allowNull - * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. + * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. * @param minValue - * Lowest legal value for input. + * Lowest legal value for input. * @param maxValue - * Highest legal value for input. + * Highest legal value for input. * * @return A validated number as a double. * * @throws ValidationException * @throws IntrusionException - */ - Double getValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull) throws ValidationException, IntrusionException; - - /** - * Calls getValidSafeHTML with the supplied errorList to capture ValidationExceptions - */ - Double getValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Calls getValidInteger and returns true if no exceptions are thrown. - */ - boolean isValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull) throws IntrusionException; - - /** - * Calls getValidInteger and returns true if no exceptions are thrown. - */ - boolean isValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Returns a validated integer. Invalid input - * will generate a descriptive ValidationException, and input that is clearly an attack - * will generate a descriptive IntrusionException. - * - * @param context - * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. + */ + Double getValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull) throws ValidationException, IntrusionException; + + /** + * Calls getValidSafeHTML with the supplied errorList to capture ValidationExceptions + */ + Double getValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Calls getValidInteger and returns true if no exceptions are thrown. + */ + boolean isValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull) throws IntrusionException; + + /** + * Calls getValidInteger and returns true if no exceptions are thrown. + */ + boolean isValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Returns a validated integer. Invalid input + * will generate a descriptive ValidationException, and input that is clearly an attack + * will generate a descriptive IntrusionException. + * + * @param context + * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. * @param input - * The actual input data to validate. + * The actual input data to validate. * @param allowNull - * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. + * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. * @param minValue - * Lowest legal value for input. + * Lowest legal value for input. * @param maxValue - * Highest legal value for input. + * Highest legal value for input. * * @return A validated number as an integer. * * @throws ValidationException * @throws IntrusionException - */ - Integer getValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull) throws ValidationException, IntrusionException; - - /** - * Calls getValidInteger with the supplied errorList to capture ValidationExceptions - */ - Integer getValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Calls getValidDouble and returns true if no exceptions are thrown. - */ - boolean isValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull) throws IntrusionException; - - /** - * Calls getValidDouble and returns true if no exceptions are thrown. - */ - boolean isValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Returns a validated real number as a double. Invalid input - * will generate a descriptive ValidationException, and input that is clearly an attack - * will generate a descriptive IntrusionException. - * - * @param context - * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. + */ + Integer getValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull) throws ValidationException, IntrusionException; + + /** + * Calls getValidInteger with the supplied errorList to capture ValidationExceptions + */ + Integer getValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Calls getValidDouble and returns true if no exceptions are thrown. + */ + boolean isValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull) throws IntrusionException; + + /** + * Calls getValidDouble and returns true if no exceptions are thrown. + */ + boolean isValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Returns a validated real number as a double. Invalid input + * will generate a descriptive ValidationException, and input that is clearly an attack + * will generate a descriptive IntrusionException. + * + * @param context + * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. * @param input - * The actual input data to validate. + * The actual input data to validate. * @param allowNull - * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. + * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. * @param minValue - * Lowest legal value for input. + * Lowest legal value for input. * @param maxValue - * Highest legal value for input. + * Highest legal value for input. * * @return A validated real number as a double. * * @throws ValidationException * @throws IntrusionException - */ - Double getValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull) throws ValidationException, IntrusionException; - - /** - * Calls getValidDouble with the supplied errorList to capture ValidationExceptions - */ - Double getValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Calls getValidFileContent and returns true if no exceptions are thrown. - */ - boolean isValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull) throws IntrusionException; - - /** - * Calls getValidFileContent and returns true if no exceptions are thrown. - */ - boolean isValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Returns validated file content as a byte array. This is a good place to check for max file size, allowed character sets, and do virus scans. Invalid input - * will generate a descriptive ValidationException, and input that is clearly an attack - * will generate a descriptive IntrusionException. - * - * @param context - * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. - * @param input - * The actual input data to validate. - * @param maxBytes - * The maximum number of bytes allowed in a legal file. - * @param allowNull - * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. - * - * @return A byte array containing valid file content. - * - * @throws ValidationException - * @throws IntrusionException - */ - byte[] getValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull) throws ValidationException, IntrusionException; - - /** - * Calls getValidFileContent with the supplied errorList to capture ValidationExceptions - */ - byte[] getValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Calls getValidFileUpload and returns true if no exceptions are thrown. - */ - boolean isValidFileUpload(String context, String filepath, String filename, File parent, byte[] content, int maxBytes, boolean allowNull) throws IntrusionException; - - /** - * Calls getValidFileUpload and returns true if no exceptions are thrown. - */ - boolean isValidFileUpload(String context, String filepath, String filename, File parent, byte[] content, int maxBytes, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Validates the filepath, filename, and content of a file. Invalid input - * will generate a descriptive ValidationException, and input that is clearly an attack - * will generate a descriptive IntrusionException. - * - * @param context - * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. - * @param filepath - * The file path of the uploaded file. - * @param filename - * The filename of the uploaded file - * @param content - * A byte array containing the content of the uploaded file. - * @param maxBytes - * The max number of bytes allowed for a legal file upload. - * @param allowNull - * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. - * - * @throws ValidationException - * @throws IntrusionException - */ - void assertValidFileUpload(String context, String filepath, String filename, File parent, byte[] content, int maxBytes, List allowedExtensions, boolean allowNull) throws ValidationException, IntrusionException; - - /** - * Calls getValidFileUpload with the supplied errorList to capture ValidationExceptions - */ - void assertValidFileUpload(String context, String filepath, String filename, File parent, byte[] content, int maxBytes, List allowedExtensions, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Calls getValidListItem and returns true if no exceptions are thrown. - */ - boolean isValidListItem(String context, String input, List list) throws IntrusionException; - - /** - * Calls getValidListItem and returns true if no exceptions are thrown. - */ - boolean isValidListItem(String context, String input, List list, ValidationErrorList errorList) throws IntrusionException; - - /** - * Returns the list item that exactly matches the canonicalized input. Invalid or non-matching input - * will generate a descriptive ValidationException, and input that is clearly an attack - * will generate a descriptive IntrusionException. - * - * @param context - * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. - * @param input - * The value to search 'list' for. - * @param list - * The list to search for 'input'. - * - * @return The list item that exactly matches the canonicalized input. - * - * @throws ValidationException - * @throws IntrusionException - */ - String getValidListItem(String context, String input, List list) throws ValidationException, IntrusionException; - - /** - * Calls getValidListItem with the supplied errorList to capture ValidationExceptions - */ - String getValidListItem(String context, String input, List list, ValidationErrorList errorList) throws IntrusionException; - - /** - * Calls assertValidHTTPRequestParameterSet and returns true if no exceptions are thrown. - */ - boolean isValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set required, Set optional) throws IntrusionException; - - /** - * Calls assertValidHTTPRequestParameterSet and returns true if no exceptions are thrown. - */ - boolean isValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set required, Set optional, ValidationErrorList errorList) throws IntrusionException; - - /** - * Validates that the parameters in the current request contain all required parameters and only optional ones in - * addition. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack - * will generate a descriptive IntrusionException. - * - * @param context - * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. - * @param required - * parameters that are required to be in HTTP request - * @param optional - * additional parameters that may be in HTTP request - * - * @throws ValidationException - * @throws IntrusionException - */ - void assertValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set required, Set optional) throws ValidationException, IntrusionException; - - /** - * Calls getValidHTTPRequestParameterSet with the supplied errorList to capture ValidationExceptions - */ - void assertValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set required, Set optional, ValidationErrorList errorList) throws IntrusionException; - - /** - * Calls getValidPrintable and returns true if no exceptions are thrown. - */ - boolean isValidPrintable(String context, char[] input, int maxLength, boolean allowNull) throws IntrusionException; + */ + Double getValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull) throws ValidationException, IntrusionException; + + /** + * Calls getValidDouble with the supplied errorList to capture ValidationExceptions + */ + Double getValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Calls getValidFileContent and returns true if no exceptions are thrown. + */ + boolean isValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull) throws IntrusionException; + + /** + * Calls getValidFileContent and returns true if no exceptions are thrown. + */ + boolean isValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Returns validated file content as a byte array. This is a good place to check for max file size, allowed character sets, and do virus scans. Invalid input + * will generate a descriptive ValidationException, and input that is clearly an attack + * will generate a descriptive IntrusionException. + * + * @param context + * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. + * @param input + * The actual input data to validate. + * @param maxBytes + * The maximum number of bytes allowed in a legal file. + * @param allowNull + * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. + * + * @return A byte array containing valid file content. + * + * @throws ValidationException + * @throws IntrusionException + */ + byte[] getValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull) throws ValidationException, IntrusionException; + + /** + * Calls getValidFileContent with the supplied errorList to capture ValidationExceptions + */ + byte[] getValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Calls getValidFileUpload and returns true if no exceptions are thrown. + */ + boolean isValidFileUpload(String context, String filepath, String filename, File parent, byte[] content, int maxBytes, boolean allowNull) throws IntrusionException; + + /** + * Calls getValidFileUpload and returns true if no exceptions are thrown. + */ + boolean isValidFileUpload(String context, String filepath, String filename, File parent, byte[] content, int maxBytes, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Validates the filepath, filename, and content of a file. Invalid input + * will generate a descriptive ValidationException, and input that is clearly an attack + * will generate a descriptive IntrusionException. + * + * @param context + * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. + * @param filepath + * The file path of the uploaded file. + * @param filename + * The filename of the uploaded file + * @param content + * A byte array containing the content of the uploaded file. + * @param maxBytes + * The max number of bytes allowed for a legal file upload. + * @param allowNull + * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. + * + * @throws ValidationException + * @throws IntrusionException + */ + void assertValidFileUpload(String context, String filepath, String filename, File parent, byte[] content, int maxBytes, List allowedExtensions, boolean allowNull) throws ValidationException, IntrusionException; + + /** + * Calls getValidFileUpload with the supplied errorList to capture ValidationExceptions + */ + void assertValidFileUpload(String context, String filepath, String filename, File parent, byte[] content, int maxBytes, List allowedExtensions, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Calls getValidListItem and returns true if no exceptions are thrown. + */ + boolean isValidListItem(String context, String input, List list) throws IntrusionException; + + /** + * Calls getValidListItem and returns true if no exceptions are thrown. + */ + boolean isValidListItem(String context, String input, List list, ValidationErrorList errorList) throws IntrusionException; + + /** + * Returns the list item that exactly matches the canonicalized input. Invalid or non-matching input + * will generate a descriptive ValidationException, and input that is clearly an attack + * will generate a descriptive IntrusionException. + * + * @param context + * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. + * @param input + * The value to search 'list' for. + * @param list + * The list to search for 'input'. + * + * @return The list item that exactly matches the canonicalized input. + * + * @throws ValidationException + * @throws IntrusionException + */ + String getValidListItem(String context, String input, List list) throws ValidationException, IntrusionException; + + /** + * Calls getValidListItem with the supplied errorList to capture ValidationExceptions + */ + String getValidListItem(String context, String input, List list, ValidationErrorList errorList) throws IntrusionException; + + /** + * Calls assertValidHTTPRequestParameterSet and returns true if no exceptions are thrown. + */ + boolean isValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set required, Set optional) throws IntrusionException; + + /** + * Calls assertValidHTTPRequestParameterSet and returns true if no exceptions are thrown. + */ + boolean isValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set required, Set optional, ValidationErrorList errorList) throws IntrusionException; + + /** + * Validates that the parameters in the current request contain all required parameters and only optional ones in + * addition. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack + * will generate a descriptive IntrusionException. + * + * @param context + * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. + * @param required + * parameters that are required to be in HTTP request + * @param optional + * additional parameters that may be in HTTP request + * + * @throws ValidationException + * @throws IntrusionException + */ + void assertValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set required, Set optional) throws ValidationException, IntrusionException; + + /** + * Calls getValidHTTPRequestParameterSet with the supplied errorList to capture ValidationExceptions + */ + void assertValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set required, Set optional, ValidationErrorList errorList) throws IntrusionException; + + /** + * Calls getValidPrintable and returns true if no exceptions are thrown. + */ + boolean isValidPrintable(String context, char[] input, int maxLength, boolean allowNull) throws IntrusionException; /** - * Calls getValidPrintable and returns true if no exceptions are thrown. - */ - boolean isValidPrintable(String context, char[] input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Returns canonicalized and validated printable characters as a byte array. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack - * will generate a descriptive IntrusionException. - * - * @param context - * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. - * @param input - * data to be returned as valid and printable - * @param maxLength - * Maximum number of bytes stored in 'input' - * @param allowNull - * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. - * - * @return a byte array containing only printable characters, made up of data from 'input' - * - * @throws ValidationException - */ - char[] getValidPrintable(String context, char[] input, int maxLength, boolean allowNull) throws ValidationException; - - /** - * Calls getValidPrintable with the supplied errorList to capture ValidationExceptions - */ - char[] getValidPrintable(String context, char[] input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - - /** - * Calls getValidPrintable and returns true if no exceptions are thrown. - */ - boolean isValidPrintable(String context, String input, int maxLength, boolean allowNull) throws IntrusionException; + * Calls getValidPrintable and returns true if no exceptions are thrown. + */ + boolean isValidPrintable(String context, char[] input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Returns canonicalized and validated printable characters as a byte array. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack + * will generate a descriptive IntrusionException. + * + * @param context + * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. + * @param input + * data to be returned as valid and printable + * @param maxLength + * Maximum number of bytes stored in 'input' + * @param allowNull + * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. + * + * @return a byte array containing only printable characters, made up of data from 'input' + * + * @throws ValidationException + */ + char[] getValidPrintable(String context, char[] input, int maxLength, boolean allowNull) throws ValidationException; + + /** + * Calls getValidPrintable with the supplied errorList to capture ValidationExceptions + */ + char[] getValidPrintable(String context, char[] input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + + /** + * Calls getValidPrintable and returns true if no exceptions are thrown. + */ + boolean isValidPrintable(String context, String input, int maxLength, boolean allowNull) throws IntrusionException; /** - * Calls getValidPrintable and returns true if no exceptions are thrown. - */ - boolean isValidPrintable(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Returns canonicalized and validated printable characters as a String. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack - * will generate a descriptive IntrusionException. - * - * @param context - * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. - * @param input - * data to be returned as valid and printable - * @param maxLength - * Maximum number of bytes stored in 'input' after canonicalization - * @param allowNull - * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. - * - * @return a String containing only printable characters, made up of data from 'input' - * - * @throws ValidationException - */ - String getValidPrintable(String context, String input, int maxLength, boolean allowNull) throws ValidationException; - - /** - * Calls getValidPrintable with the supplied errorList to capture ValidationExceptions - */ - String getValidPrintable(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Calls getValidRedirectLocation and returns true if no exceptions are thrown. - */ - boolean isValidRedirectLocation(String context, String input, boolean allowNull); + * Calls getValidPrintable and returns true if no exceptions are thrown. + */ + boolean isValidPrintable(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Returns canonicalized and validated printable characters as a String. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack + * will generate a descriptive IntrusionException. + * + * @param context + * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. + * @param input + * data to be returned as valid and printable + * @param maxLength + * Maximum number of bytes stored in 'input' after canonicalization + * @param allowNull + * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. + * + * @return a String containing only printable characters, made up of data from 'input' + * + * @throws ValidationException + */ + String getValidPrintable(String context, String input, int maxLength, boolean allowNull) throws ValidationException; + + /** + * Calls getValidPrintable with the supplied errorList to capture ValidationExceptions + */ + String getValidPrintable(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Calls getValidRedirectLocation and returns true if no exceptions are thrown. + */ + boolean isValidRedirectLocation(String context, String input, boolean allowNull); /** - * Calls getValidRedirectLocation and returns true if no exceptions are thrown. - */ - boolean isValidRedirectLocation(String context, String input, boolean allowNull, ValidationErrorList errorList); - - /** - * Returns a canonicalized and validated redirect location as a String. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack - * will generate a descriptive IntrusionException. - * - * @param context - * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. - * @param input - * redirect location to be returned as valid, according to encoding rules set in "ESAPI.properties" - * @param allowNull - * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. - * - * @return A canonicalized and validated redirect location, as defined in "ESAPI.properties" - * - * @throws ValidationException - * @throws IntrusionException - */ - String getValidRedirectLocation(String context, String input, boolean allowNull) throws ValidationException, IntrusionException; - - /** - * Calls getValidRedirectLocation with the supplied errorList to capture ValidationExceptions - */ - String getValidRedirectLocation(String context, String input, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; - - /** - * Reads from an input stream until end-of-line or a maximum number of - * characters. This method protects against the inherent denial of service - * attack in reading until the end of a line. If an attacker doesn't ever - * send a newline character, then a normal input stream reader will read - * until all memory is exhausted and the platform throws an OutOfMemoryError - * and probably terminates. - * - * @param inputStream - * The InputStream from which to read data - * @param maxLength - * Maximum characters allowed to be read in per line - * - * @return a String containing the current line of inputStream - * - * @throws ValidationException - */ - String safeReadLine(InputStream inputStream, int maxLength) throws ValidationException; - - /** - * Parses and ensures that the URI in question is a valid RFC-3986 URI. This simplifies - * the kind of regex required for subsequent validation to mitigate regex-based DoS attacks. - * - * @see RFC-3986. - * - * @param context - * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any - * logging or error handling that is done with respect to the value passed in. - * @param input - * redirect location to be returned as valid, according to encoding rules set in "ESAPI.properties" - * @param allowNull - * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an - * empty String will throw a ValidationException. - * - * @return True if the URI is valid - * @throws ValidationException - */ - boolean isValidURI(String context, String input, boolean allowNull); - - /** - * Will return a {@code URI} object that will represent a fully parsed and legal URI - * as specified in RFC-3986. - * - * @param input String - * @return URI object representing a parsed URI, or {@code null} if the URI was non-compliant in some way. - */ - URI getRfcCompliantURI(String input); - + * Calls getValidRedirectLocation and returns true if no exceptions are thrown. + */ + boolean isValidRedirectLocation(String context, String input, boolean allowNull, ValidationErrorList errorList); + + /** + * Returns a canonicalized and validated redirect location as a String. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack + * will generate a descriptive IntrusionException. + * + * @param context + * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any logging or error handling that is done with respect to the value passed in. + * @param input + * redirect location to be returned as valid, according to encoding rules set in "ESAPI.properties" + * @param allowNull + * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. + * + * @return A canonicalized and validated redirect location, as defined in "ESAPI.properties" + * + * @throws ValidationException + * @throws IntrusionException + */ + String getValidRedirectLocation(String context, String input, boolean allowNull) throws ValidationException, IntrusionException; + + /** + * Calls getValidRedirectLocation with the supplied errorList to capture ValidationExceptions + */ + String getValidRedirectLocation(String context, String input, boolean allowNull, ValidationErrorList errorList) throws IntrusionException; + + /** + * Reads from an input stream until end-of-line or a maximum number of + * characters. This method protects against the inherent denial of service + * attack in reading until the end of a line. If an attacker doesn't ever + * send a newline character, then a normal input stream reader will read + * until all memory is exhausted and the platform throws an OutOfMemoryError + * and probably terminates. + * + * @param inputStream + * The InputStream from which to read data + * @param maxLength + * Maximum characters allowed to be read in per line + * + * @return a String containing the current line of inputStream + * + * @throws ValidationException + */ + String safeReadLine(InputStream inputStream, int maxLength) throws ValidationException; + + /** + * Parses and ensures that the URI in question is a valid RFC-3986 URI. This simplifies + * the kind of regex required for subsequent validation to mitigate regex-based DoS attacks. + * + * @see RFC-3986. + * + * @param context + * A descriptive name of the parameter that you are validating (e.g., LoginPage_UsernameField). This value is used by any + * logging or error handling that is done with respect to the value passed in. + * @param input + * redirect location to be returned as valid, according to encoding rules set in "ESAPI.properties" + * @param allowNull + * If allowNull is true then an input that is NULL or an empty string will be legal. If allowNull is false then NULL or an + * empty String will throw a ValidationException. + * + * @return True if the URI is valid + * @throws ValidationException + */ + boolean isValidURI(String context, String input, boolean allowNull); + + /** + * Will return a {@code URI} object that will represent a fully parsed and legal URI + * as specified in RFC-3986. + * + * @param input String + * @return URI object representing a parsed URI, or {@code null} if the URI was non-compliant in some way. + */ + URI getRfcCompliantURI(String input); + } diff --git a/src/main/java/org/owasp/esapi/codecs/AbstractCharacterCodec.java b/src/main/java/org/owasp/esapi/codecs/AbstractCharacterCodec.java index ed73e4bd9..4b366f5cf 100644 --- a/src/main/java/org/owasp/esapi/codecs/AbstractCharacterCodec.java +++ b/src/main/java/org/owasp/esapi/codecs/AbstractCharacterCodec.java @@ -27,21 +27,21 @@ * */ public abstract class AbstractCharacterCodec extends AbstractCodec { - /* (non-Javadoc) - * @see org.owasp.esapi.codecs.Codec#decode(java.lang.String) - */ - @Override - public String decode(String input) { - StringBuilder sb = new StringBuilder(); - PushbackSequence pbs = new PushbackString(input); - while (pbs.hasNext()) { - Character c = decodeCharacter(pbs); - if (c != null) { - sb.append(c); - } else { - sb.append(pbs.next()); - } - } - return sb.toString(); - } + /* (non-Javadoc) + * @see org.owasp.esapi.codecs.Codec#decode(java.lang.String) + */ + @Override + public String decode(String input) { + StringBuilder sb = new StringBuilder(); + PushbackSequence pbs = new PushbackString(input); + while (pbs.hasNext()) { + Character c = decodeCharacter(pbs); + if (c != null) { + sb.append(c); + } else { + sb.append(pbs.next()); + } + } + return sb.toString(); + } } diff --git a/src/main/java/org/owasp/esapi/codecs/AbstractCodec.java b/src/main/java/org/owasp/esapi/codecs/AbstractCodec.java index 7192bae20..996c7d159 100644 --- a/src/main/java/org/owasp/esapi/codecs/AbstractCodec.java +++ b/src/main/java/org/owasp/esapi/codecs/AbstractCodec.java @@ -31,131 +31,131 @@ */ public abstract class AbstractCodec implements Codec { - /** - * Initialize an array to mark which characters are to be encoded. Store the hex - * string for that character to save time later. If the character shouldn't be - * encoded, then store null. - */ - private final String[] hex = new String[256]; + /** + * Initialize an array to mark which characters are to be encoded. Store the hex + * string for that character to save time later. If the character shouldn't be + * encoded, then store null. + */ + private final String[] hex = new String[256]; - /** - * Default constructor - */ - public AbstractCodec() { - for ( char c = 0; c < 0xFF; c++ ) { - if ( c >= 0x30 && c <= 0x39 || c >= 0x41 && c <= 0x5A || c >= 0x61 && c <= 0x7A ) { - hex[c] = null; - } else { - hex[c] = toHex(c).intern(); - } - } - } + /** + * Default constructor + */ + public AbstractCodec() { + for ( char c = 0; c < 0xFF; c++ ) { + if ( c >= 0x30 && c <= 0x39 || c >= 0x41 && c <= 0x5A || c >= 0x61 && c <= 0x7A ) { + hex[c] = null; + } else { + hex[c] = toHex(c).intern(); + } + } + } - /** - * WARNING!! {@code Character} based Codecs will silently transform code points that are not - * legal UTF code points into garbage data as they will cast them to {@code char}s. - *

    - * If you are implementing an {@code Integer} based codec, these will be silently discarded - * based on the return from {@code Character.isValidCodePoint( int )}. This is the preferred - * behavior moving forward. - * - * - * {@inheritDoc} - */ - @Override - public String encode(char[] immune, String input) { - StringBuilder sb = new StringBuilder(); - for(int offset = 0; offset < input.length(); ) { - final int point = input.codePointAt(offset); - if (Character.isBmpCodePoint(point)) { - //We can then safely cast this to char and maintain legacy behavior. - sb.append(encodeCharacter(immune, new Character((char) point))); - } else { - sb.append(encodeCharacter(immune, point)); - } - offset += Character.charCount(point); - } - return sb.toString(); - } + /** + * WARNING!! {@code Character} based Codecs will silently transform code points that are not + * legal UTF code points into garbage data as they will cast them to {@code char}s. + *

    + * If you are implementing an {@code Integer} based codec, these will be silently discarded + * based on the return from {@code Character.isValidCodePoint( int )}. This is the preferred + * behavior moving forward. + * + * + * {@inheritDoc} + */ + @Override + public String encode(char[] immune, String input) { + StringBuilder sb = new StringBuilder(); + for(int offset = 0; offset < input.length(); ) { + final int point = input.codePointAt(offset); + if (Character.isBmpCodePoint(point)) { + //We can then safely cast this to char and maintain legacy behavior. + sb.append(encodeCharacter(immune, new Character((char) point))); + } else { + sb.append(encodeCharacter(immune, point)); + } + offset += Character.charCount(point); + } + return sb.toString(); + } - /** - * WARNING!!!! Passing a standard char to this method will resolve to the - * @see #encodeCharacter( char[], int ) - * method instead of this one!!! YOU HAVE BEEN WARNED!!!! - * - * {@inheritDoc} - */ - @Override - public String encodeCharacter( char[] immune, Character c ) { - return ""+c; - } - - public String encodeCharacter(char[] immune, char c) { - throw new IllegalArgumentException("You tried to call encodeCharacter with a char. Nope. Use Character instead!"); - } - - /* (non-Javadoc) - * @see org.owasp.esapi.codecs.Codec#encodeCharacter(char[], int) - */ - @Override - public String encodeCharacter( char[] immune, int codePoint ) { - String rval = ""; - if(Character.isValidCodePoint(codePoint)){ - rval = new StringBuilder().appendCodePoint(codePoint).toString(); - } - return rval; - } + /** + * WARNING!!!! Passing a standard char to this method will resolve to the + * @see #encodeCharacter( char[], int ) + * method instead of this one!!! YOU HAVE BEEN WARNED!!!! + * + * {@inheritDoc} + */ + @Override + public String encodeCharacter( char[] immune, Character c ) { + return ""+c; + } + + public String encodeCharacter(char[] immune, char c) { + throw new IllegalArgumentException("You tried to call encodeCharacter with a char. Nope. Use Character instead!"); + } + + /* (non-Javadoc) + * @see org.owasp.esapi.codecs.Codec#encodeCharacter(char[], int) + */ + @Override + public String encodeCharacter( char[] immune, int codePoint ) { + String rval = ""; + if(Character.isValidCodePoint(codePoint)){ + rval = new StringBuilder().appendCodePoint(codePoint).toString(); + } + return rval; + } - /* (non-Javadoc) - * @see org.owasp.esapi.codecs.Codec#decodeCharacter(org.owasp.esapi.codecs.PushbackString) - */ - @Override - public T decodeCharacter( PushbackSequence input ) { - return input.next(); - } + /* (non-Javadoc) + * @see org.owasp.esapi.codecs.Codec#decodeCharacter(org.owasp.esapi.codecs.PushbackString) + */ + @Override + public T decodeCharacter( PushbackSequence input ) { + return input.next(); + } - /** - * {@inheritDoc} - */ - public String getHexForNonAlphanumeric(char c) { - if(c<0xFF) - return hex[c]; - return toHex(c); - } - - /** - * {@inheritDoc} - */ - public String getHexForNonAlphanumeric(int c) { - if (c<0xFF) { - return hex[c]; - } else { - return toHex(c); - } - } + /** + * {@inheritDoc} + */ + public String getHexForNonAlphanumeric(char c) { + if(c<0xFF) + return hex[c]; + return toHex(c); + } + + /** + * {@inheritDoc} + */ + public String getHexForNonAlphanumeric(int c) { + if (c<0xFF) { + return hex[c]; + } else { + return toHex(c); + } + } - public String toOctal(char c) { - return Integer.toOctalString(c); - } + public String toOctal(char c) { + return Integer.toOctalString(c); + } - public String toHex(char c) { - return Integer.toHexString(c); - } - - public String toHex(int c) { - return Integer.toHexString(c); - } + public String toHex(char c) { + return Integer.toHexString(c); + } + + public String toHex(int c) { + return Integer.toHexString(c); + } - /** - * {@inheritDoc} - */ - public boolean containsCharacter( char c, char[] array ) { - for (char ch : array) { - if (c == ch) return true; - } - return false; - } + /** + * {@inheritDoc} + */ + public boolean containsCharacter( char c, char[] array ) { + for (char ch : array) { + if (c == ch) return true; + } + return false; + } } diff --git a/src/main/java/org/owasp/esapi/codecs/AbstractIntegerCodec.java b/src/main/java/org/owasp/esapi/codecs/AbstractIntegerCodec.java index cf522e92f..cb9a61ff2 100644 --- a/src/main/java/org/owasp/esapi/codecs/AbstractIntegerCodec.java +++ b/src/main/java/org/owasp/esapi/codecs/AbstractIntegerCodec.java @@ -30,21 +30,21 @@ */ public class AbstractIntegerCodec extends AbstractCodec { - /** - * {@inheritDoc} - */ - @Override - public String decode(String input) { - StringBuilder sb = new StringBuilder(); - PushbackSequence pbs = new PushBackSequenceImpl(input); - while (pbs.hasNext()) { - Integer c = decodeCharacter(pbs); - if (c != null && Character.isValidCodePoint(c)) { - sb.appendCodePoint(c); - } else { - sb.appendCodePoint(pbs.next()); - } - } - return sb.toString(); - } + /** + * {@inheritDoc} + */ + @Override + public String decode(String input) { + StringBuilder sb = new StringBuilder(); + PushbackSequence pbs = new PushBackSequenceImpl(input); + while (pbs.hasNext()) { + Integer c = decodeCharacter(pbs); + if (c != null && Character.isValidCodePoint(c)) { + sb.appendCodePoint(c); + } else { + sb.appendCodePoint(pbs.next()); + } + } + return sb.toString(); + } } diff --git a/src/main/java/org/owasp/esapi/codecs/AbstractPushbackSequence.java b/src/main/java/org/owasp/esapi/codecs/AbstractPushbackSequence.java index 7ebe0f42a..dfe640fbc 100644 --- a/src/main/java/org/owasp/esapi/codecs/AbstractPushbackSequence.java +++ b/src/main/java/org/owasp/esapi/codecs/AbstractPushbackSequence.java @@ -29,42 +29,42 @@ * @param */ public abstract class AbstractPushbackSequence implements PushbackSequence { - protected String input; - protected T pushback; - protected T temp; - protected int index = 0; - protected int mark = 0; + protected String input; + protected T pushback; + protected T temp; + protected int index = 0; + protected int mark = 0; - public AbstractPushbackSequence(String input) { - this.input = input; - } + public AbstractPushbackSequence(String input) { + this.input = input; + } - /** - * {@inheritDoc} - */ - public void pushback(T c) { - pushback = c; - } + /** + * {@inheritDoc} + */ + public void pushback(T c) { + pushback = c; + } - /** - * {@inheritDoc} - */ - public int index() { - return index; - } + /** + * {@inheritDoc} + */ + public int index() { + return index; + } - /** - * {@inheritDoc} - */ - public boolean hasNext() { - if (pushback != null) - return true; - if (input == null) - return false; - if (input.length() == 0) - return false; - if (index >= input.length()) - return false; - return true; - } + /** + * {@inheritDoc} + */ + public boolean hasNext() { + if (pushback != null) + return true; + if (input == null) + return false; + if (input.length() == 0) + return false; + if (index >= input.length()) + return false; + return true; + } } diff --git a/src/main/java/org/owasp/esapi/codecs/CSSCodec.java b/src/main/java/org/owasp/esapi/codecs/CSSCodec.java index 152aa206c..548ce3a5e 100644 --- a/src/main/java/org/owasp/esapi/codecs/CSSCodec.java +++ b/src/main/java/org/owasp/esapi/codecs/CSSCodec.java @@ -29,171 +29,171 @@ */ public class CSSCodec extends AbstractCharacterCodec { - private static final Character REPLACEMENT = '\ufffd'; - //rgb (###,###,###) OR rgb(###%,###%,###%) - //([rR][gG][bB])\s*\(\s*\d{1,3}\s*(\%)?\s*,\s*\d{1,3}\s*(\%)?\s*,\s*\d{1,3}\s*(\%)?\s*\) - private static final String RGB_TRPLT = "([rR][gG][bB])\\s*\\(\\s*\\d{1,3}\\s*(\\%)?\\s*,\\s*\\d{1,3}\\s*(\\%)?\\s*,\\s*\\d{1,3}\\s*(\\%)?\\s*\\)"; - private static final Pattern RGB_TRPLT_PATTERN = Pattern.compile(RGB_TRPLT); - - @Override - public String encode(char[] immune, String input) { - EncodingPatternPreservation tripletCheck = new EncodingPatternPreservation(RGB_TRPLT_PATTERN); - - String inputChk = tripletCheck.captureAndReplaceMatches(input); - - String result = super.encode(immune, inputChk); - - return tripletCheck.restoreOriginalContent(result); - } + private static final Character REPLACEMENT = '\ufffd'; + //rgb (###,###,###) OR rgb(###%,###%,###%) + //([rR][gG][bB])\s*\(\s*\d{1,3}\s*(\%)?\s*,\s*\d{1,3}\s*(\%)?\s*,\s*\d{1,3}\s*(\%)?\s*\) + private static final String RGB_TRPLT = "([rR][gG][bB])\\s*\\(\\s*\\d{1,3}\\s*(\\%)?\\s*,\\s*\\d{1,3}\\s*(\\%)?\\s*,\\s*\\d{1,3}\\s*(\\%)?\\s*\\)"; + private static final Pattern RGB_TRPLT_PATTERN = Pattern.compile(RGB_TRPLT); + + @Override + public String encode(char[] immune, String input) { + EncodingPatternPreservation tripletCheck = new EncodingPatternPreservation(RGB_TRPLT_PATTERN); + + String inputChk = tripletCheck.captureAndReplaceMatches(input); + + String result = super.encode(immune, inputChk); + + return tripletCheck.restoreOriginalContent(result); + } /** - * {@inheritDoc} - * + * {@inheritDoc} + * * Returns backslash encoded character. * * @param immune */ public String encodeCharacter(char[] immune, Character c) { - // check for immune characters - if ( containsCharacter(c, immune ) ) { - return ""+c; - } - - // check for alphanumeric characters - String hex = super.getHexForNonAlphanumeric(c); - if ( hex == null ) { - return ""+c; - } - - // return the hex and end in whitespace to terminate + // check for immune characters + if ( containsCharacter(c, immune ) ) { + return ""+c; + } + + // check for alphanumeric characters + String hex = super.getHexForNonAlphanumeric(c); + if ( hex == null ) { + return ""+c; + } + + // return the hex and end in whitespace to terminate return "\\" + hex + " "; } - /** - * {@inheritDoc} - * - * Returns the decoded version of the character starting at index, - * or null if no decoding is possible. - */ + /** + * {@inheritDoc} + * + * Returns the decoded version of the character starting at index, + * or null if no decoding is possible. + */ @SuppressWarnings("fallthrough") public Character decodeCharacter(PushbackSequence input) - { - input.mark(); - Character first = input.next(); - if (first == null || first != '\\') - { - input.reset(); - return null; - } + { + input.mark(); + Character first = input.next(); + if (first == null || first != '\\') + { + input.reset(); + return null; + } - Character second = input.next(); - if (second == null) { - input.reset(); - return null; - } + Character second = input.next(); + if (second == null) { + input.reset(); + return null; + } - /* From css 2.1 spec: - * http://www.w3.org/TR/CSS21/syndata.html#characters - * - * First, inside a string, a backslash followed by a - * newline is ignored (i.e., the string is deemed not - * to contain either the backslash or the newline). - * - * Second, it cancels the meaning of special CSS - * characters. Except within CSS comments, any character - * (except a hexadecimal digit, linefeed, carriage return, - * or form feed) can be escaped with a backslash to - * remove its special meaning. For example, "\"" is a string - * consisting of one double quote. Style sheet - * preprocessors must not remove these backslashes - * from a style sheet since that would change the style - * sheet's meaning. - * - * Third, backslash escapes allow authors to refer to - * characters they cannot easily put in a document. In - * this case, the backslash is followed by at most six - * hexadecimal digits (0..9A..F), which stand for the ISO - * 10646 ([ISO10646]) character with that number, which - * must not be zero. (It is undefined in CSS 2.1 what - * happens if a style sheet does contain a character with - * Unicode codepoint zero.) If a character in the range - * [0-9a-fA-F] follows the hexadecimal number, the end - * of the number needs to be made clear. There are two - * ways to do that: - * - * 1. with a space (or other white space character): - * "\26 B" ("&B"). In this case, user agents should - * treat a "CR/LF" pair (U+000D/U+000A) as a single - * white space character. - * - * 2. by providing exactly 6 hexadecimal digits: - * "\000026B" ("&B") - * - * In fact, these two methods may be combined. Only one - * white space character is ignored after a hexadecimal - * escape. Note that this means that a "real" space - * after the escape sequence must itself either be - * escaped or doubled. - * - * If the number is outside the range allowed by Unicode - * (e.g., "\110000" is above the maximum 10FFFF allowed in - * current Unicode), the UA may replace the escape with - * the "replacement character" (U+FFFD). If the character - * is to be displayed, the UA should show a visible - * symbol, such as a "missing character" glyph (cf. 15.2, - * point 5). - */ + /* From css 2.1 spec: + * http://www.w3.org/TR/CSS21/syndata.html#characters + * + * First, inside a string, a backslash followed by a + * newline is ignored (i.e., the string is deemed not + * to contain either the backslash or the newline). + * + * Second, it cancels the meaning of special CSS + * characters. Except within CSS comments, any character + * (except a hexadecimal digit, linefeed, carriage return, + * or form feed) can be escaped with a backslash to + * remove its special meaning. For example, "\"" is a string + * consisting of one double quote. Style sheet + * preprocessors must not remove these backslashes + * from a style sheet since that would change the style + * sheet's meaning. + * + * Third, backslash escapes allow authors to refer to + * characters they cannot easily put in a document. In + * this case, the backslash is followed by at most six + * hexadecimal digits (0..9A..F), which stand for the ISO + * 10646 ([ISO10646]) character with that number, which + * must not be zero. (It is undefined in CSS 2.1 what + * happens if a style sheet does contain a character with + * Unicode codepoint zero.) If a character in the range + * [0-9a-fA-F] follows the hexadecimal number, the end + * of the number needs to be made clear. There are two + * ways to do that: + * + * 1. with a space (or other white space character): + * "\26 B" ("&B"). In this case, user agents should + * treat a "CR/LF" pair (U+000D/U+000A) as a single + * white space character. + * + * 2. by providing exactly 6 hexadecimal digits: + * "\000026B" ("&B") + * + * In fact, these two methods may be combined. Only one + * white space character is ignored after a hexadecimal + * escape. Note that this means that a "real" space + * after the escape sequence must itself either be + * escaped or doubled. + * + * If the number is outside the range allowed by Unicode + * (e.g., "\110000" is above the maximum 10FFFF allowed in + * current Unicode), the UA may replace the escape with + * the "replacement character" (U+FFFD). If the character + * is to be displayed, the UA should show a visible + * symbol, such as a "missing character" glyph (cf. 15.2, + * point 5). + */ - switch(second) - { // special whitespace cases. I assume they mean - // for all of these to qualify as a "new - // line." Otherwise there is no specification - // of what to do for \f - case '\r': - if(input.peek('\n')) - input.next(); - // fall through - case '\n': // Intentional fall through - case '\f': // Intentional fall through - // bs followed by new line replaced by nothing - case '\u0000': // skip NUL for now too - return decodeCharacter(input); - } + switch(second) + { // special whitespace cases. I assume they mean + // for all of these to qualify as a "new + // line." Otherwise there is no specification + // of what to do for \f + case '\r': + if(input.peek('\n')) + input.next(); + // fall through + case '\n': // Intentional fall through + case '\f': // Intentional fall through + // bs followed by new line replaced by nothing + case '\u0000': // skip NUL for now too + return decodeCharacter(input); + } - if (!PushbackString.isHexDigit(second)) - { // non hex digit - return second; - } + if (!PushbackString.isHexDigit(second)) + { // non hex digit + return second; + } - // Search for up to 6 hex digits following until a space - StringBuilder sb = new StringBuilder(); - sb.append(second); - for (int i = 0; i < 5; i++) - { - Character c = input.next(); - if(c == null || Character.isWhitespace(c)) - break; - if(PushbackString.isHexDigit(c)) - sb.append(c); - else - { - input.pushback(c); - break; - } - } - try - { - // parse the hex digit and create a character - int i = Integer.parseInt(sb.toString(), 16); - - if (Character.isValidCodePoint(i)) - return (char)i; - return REPLACEMENT; - } - catch (NumberFormatException e) - { - throw new IllegalStateException("Received a NumberFormateException parsing a string verified to be hex", e); - } - } + // Search for up to 6 hex digits following until a space + StringBuilder sb = new StringBuilder(); + sb.append(second); + for (int i = 0; i < 5; i++) + { + Character c = input.next(); + if(c == null || Character.isWhitespace(c)) + break; + if(PushbackString.isHexDigit(c)) + sb.append(c); + else + { + input.pushback(c); + break; + } + } + try + { + // parse the hex digit and create a character + int i = Integer.parseInt(sb.toString(), 16); + + if (Character.isValidCodePoint(i)) + return (char)i; + return REPLACEMENT; + } + catch (NumberFormatException e) + { + throw new IllegalStateException("Received a NumberFormateException parsing a string verified to be hex", e); + } + } } diff --git a/src/main/java/org/owasp/esapi/codecs/Codec.java b/src/main/java/org/owasp/esapi/codecs/Codec.java index 1d6f2d09a..9ddb4aeb2 100644 --- a/src/main/java/org/owasp/esapi/codecs/Codec.java +++ b/src/main/java/org/owasp/esapi/codecs/Codec.java @@ -32,87 +32,87 @@ * @see org.owasp.esapi.Encoder */ public interface Codec { - /** - * Encode a String so that it can be safely used in a specific context. - * - * @param immune - * @param input - * the String to encode - * @return the encoded String - */ - public String encode(char[] immune, String input); + /** + * Encode a String so that it can be safely used in a specific context. + * + * @param immune + * @param input + * the String to encode + * @return the encoded String + */ + public String encode(char[] immune, String input); - /** - * Default implementation that should be overridden in specific codecs. - * - * @param immune - * array of chars to NOT encode. Use with caution. - * @param c - * the Character to encode - * @return - * the encoded Character - */ - public String encodeCharacter( char[] immune, Character c ); - - /** - * Default codepoint implementation that should be overridden in specific codecs. - * - * @param immune - * @param codePoint - * the integer to encode - * @return - * the encoded Character - */ - public String encodeCharacter( char[] immune, int codePoint ); + /** + * Default implementation that should be overridden in specific codecs. + * + * @param immune + * array of chars to NOT encode. Use with caution. + * @param c + * the Character to encode + * @return + * the encoded Character + */ + public String encodeCharacter( char[] immune, Character c ); + + /** + * Default codepoint implementation that should be overridden in specific codecs. + * + * @param immune + * @param codePoint + * the integer to encode + * @return + * the encoded Character + */ + public String encodeCharacter( char[] immune, int codePoint ); - /** - * Decode a String that was encoded using the encode method in this Class - * - * @param input - * the String to decode - * @return - * the decoded String - */ - public String decode(String input); + /** + * Decode a String that was encoded using the encode method in this Class + * + * @param input + * the String to decode + * @return + * the decoded String + */ + public String decode(String input); - /** - * Returns the decoded version of the next character from the input string and advances the - * current character in the PushbackSequence. If the current character is not encoded, this - * method MUST reset the PushbackString. - * - * @param input the Character to decode - * - * @return the decoded Character - */ - public T decodeCharacter( PushbackSequence input ); + /** + * Returns the decoded version of the next character from the input string and advances the + * current character in the PushbackSequence. If the current character is not encoded, this + * method MUST reset the PushbackString. + * + * @param input the Character to decode + * + * @return the decoded Character + */ + public T decodeCharacter( PushbackSequence input ); - /** - * Lookup the hex value of any character that is not alphanumeric. - * @param c The character to lookup. - * @return return null if alphanumeric or the character code in hex. - */ - public String getHexForNonAlphanumeric(char c); - - /** - * Lookup the hex value of any character that is not alphanumeric. - * @param c The character to lookup. - * @return return null if alphanumeric or the character code in hex. - */ - public String getHexForNonAlphanumeric(int c); + /** + * Lookup the hex value of any character that is not alphanumeric. + * @param c The character to lookup. + * @return return null if alphanumeric or the character code in hex. + */ + public String getHexForNonAlphanumeric(char c); + + /** + * Lookup the hex value of any character that is not alphanumeric. + * @param c The character to lookup. + * @return return null if alphanumeric or the character code in hex. + */ + public String getHexForNonAlphanumeric(int c); - public String toOctal(char c); + public String toOctal(char c); - public String toHex(char c); - - public String toHex(int c); + public String toHex(char c); + + public String toHex(int c); - /** - * Utility to search a char[] for a specific char. - * - * @param c - * @param array - * @return True if the supplied array contains the specified character. False otherwise. - */ - public boolean containsCharacter( char c, char[] array ); + /** + * Utility to search a char[] for a specific char. + * + * @param c + * @param array + * @return True if the supplied array contains the specified character. False otherwise. + */ + public boolean containsCharacter( char c, char[] array ); } diff --git a/src/main/java/org/owasp/esapi/codecs/DB2Codec.java b/src/main/java/org/owasp/esapi/codecs/DB2Codec.java index 850d9a6aa..33d0e4a59 100644 --- a/src/main/java/org/owasp/esapi/codecs/DB2Codec.java +++ b/src/main/java/org/owasp/esapi/codecs/DB2Codec.java @@ -22,47 +22,47 @@ */ public class DB2Codec extends AbstractCharacterCodec { - public String encodeCharacter(char[] immune, Character c) { + public String encodeCharacter(char[] immune, Character c) { - if (c.charValue() == '\'') - return "\'\'"; + if (c.charValue() == '\'') + return "\'\'"; - if (c.charValue() == ';') - return "."; + if (c.charValue() == ';') + return "."; - return "" + c; - } + return "" + c; + } - public Character decodeCharacter(PushbackString input) { + public Character decodeCharacter(PushbackString input) { - input.mark(); - Character first = input.next(); + input.mark(); + Character first = input.next(); - if (first == null) { - input.reset(); - return null; - } + if (first == null) { + input.reset(); + return null; + } - // if this is not an encoded character, return null + // if this is not an encoded character, return null - if (first.charValue() != '\'') { - input.reset(); - return null; - } + if (first.charValue() != '\'') { + input.reset(); + return null; + } - Character second = input.next(); + Character second = input.next(); - if (second == null) { - input.reset(); - return null; - } + if (second == null) { + input.reset(); + return null; + } - // if this is not an encoded character, return null - if (second.charValue() != '\'') { - input.reset(); - return null; - } + // if this is not an encoded character, return null + if (second.charValue() != '\'') { + input.reset(); + return null; + } - return (Character.valueOf('\'')); - } + return (Character.valueOf('\'')); + } } \ No newline at end of file diff --git a/src/main/java/org/owasp/esapi/codecs/HTMLEntityCodec.java b/src/main/java/org/owasp/esapi/codecs/HTMLEntityCodec.java index 7fc805938..0340edbac 100644 --- a/src/main/java/org/owasp/esapi/codecs/HTMLEntityCodec.java +++ b/src/main/java/org/owasp/esapi/codecs/HTMLEntityCodec.java @@ -37,18 +37,18 @@ */ public class HTMLEntityCodec extends AbstractIntegerCodec { - private static final char REPLACEMENT_CHAR = '\ufffd'; - private static final String REPLACEMENT_HEX = "fffd"; - private static final String REPLACEMENT_STR = "" + REPLACEMENT_CHAR; - private static final Map characterToEntityMap = mkCharacterToEntityMap(); + private static final char REPLACEMENT_CHAR = '\ufffd'; + private static final String REPLACEMENT_HEX = "fffd"; + private static final String REPLACEMENT_STR = "" + REPLACEMENT_CHAR; + private static final Map characterToEntityMap = mkCharacterToEntityMap(); - private static final Trie entityToCharacterTrie = mkEntityToCharacterTrie(); + private static final Trie entityToCharacterTrie = mkEntityToCharacterTrie(); /** * */ public HTMLEntityCodec() { - } + } /** * Given an array of {@code char}, scan the input {@code String} and encode unsafe @@ -59,540 +59,540 @@ public HTMLEntityCodec() { * * {@inheritDoc} */ - @Override - public String encode(char[] immune, String input) { - StringBuilder sb = new StringBuilder(); - for(int offset = 0; offset < input.length(); ){ - final int point = input.codePointAt(offset); - if(Character.isValidCodePoint(point)){ - sb.append(encodeCharacter(immune, point)); - } - offset += Character.charCount(point); - } - return sb.toString(); - } - - /** - * {@inheritDoc} - * + @Override + public String encode(char[] immune, String input) { + StringBuilder sb = new StringBuilder(); + for(int offset = 0; offset < input.length(); ){ + final int point = input.codePointAt(offset); + if(Character.isValidCodePoint(point)){ + sb.append(encodeCharacter(immune, point)); + } + offset += Character.charCount(point); + } + return sb.toString(); + } + + /** + * {@inheritDoc} + * * Encodes a codePoint for safe use in an HTML entity field. * @param immune */ - @Override - public String encodeCharacter( char[] immune, int codePoint ) { + @Override + public String encodeCharacter( char[] immune, int codePoint ) { - // check for immune characters - // Cast the codePoint to a char because we want to limit immunity to the BMP field only. - if ( containsCharacter( (char) codePoint, immune ) && Character.isValidCodePoint(codePoint)) { - return new StringBuilder().appendCodePoint(codePoint).toString(); - } - - // check for alphanumeric characters - String hex = super.getHexForNonAlphanumeric(codePoint); - if ( hex == null && Character.isValidCodePoint(codePoint)) { - return new StringBuilder().appendCodePoint(codePoint).toString(); - } - // check for illegal characters - if ( ( codePoint <= 0x1f - && codePoint != '\t' - && codePoint != '\n' - && codePoint != '\r' ) - || ( codePoint >= 0x7f && codePoint <= 0x9f ) ) - { - hex = REPLACEMENT_HEX; // Let's entity encode this instead of returning it - codePoint = REPLACEMENT_CHAR; - } - - // check if there's a defined entity - String entityName = characterToEntityMap.get(codePoint); - if (entityName != null) { - return "&" + entityName + ";"; - } - - // return the hex entity as suggested in the spec - return "&#x" + hex + ";"; - } - - /** - * {@inheritDoc} - * - * Returns the decoded version of the character starting at index, or - * null if no decoding is possible. - * - * Formats all are legal both with and without semi-colon, upper/lower case: - * &#dddd; - * &#xhhhh; - * &name; - */ - public Integer decodeCharacter( PushbackSequence input ) { - input.mark(); - Integer first = input.next(); - if ( first == null ) { - input.reset(); - return null; - } - - // if this is not an encoded character, return null - if (first != '&' ) { - input.reset(); - return null; - } - - // test for numeric encodings - Integer second = input.next(); - if ( second == null ) { - input.reset(); - return null; - } - - if (second == '#' ) { - // handle numbers - Integer c = getNumericEntity( input ); - if ( c != null ) return c; - } else if ( Character.isLetter( second ) ) { - // handle entities - input.pushback( second ); - Integer c = getNamedEntity( input ); - if ( c != null ) return c; - } - input.reset(); - return null; - } - - /** - * getNumericEntry checks input to see if it is a numeric entity - * - * @param input - * The input to test for being a numeric entity - * - * @return - * null if input is null, the character of input after decoding - */ - private Integer getNumericEntity( PushbackSequence input ) { - Integer first = input.peek(); - if ( first == null ) return null; + // check for immune characters + // Cast the codePoint to a char because we want to limit immunity to the BMP field only. + if ( containsCharacter( (char) codePoint, immune ) && Character.isValidCodePoint(codePoint)) { + return new StringBuilder().appendCodePoint(codePoint).toString(); + } + + // check for alphanumeric characters + String hex = super.getHexForNonAlphanumeric(codePoint); + if ( hex == null && Character.isValidCodePoint(codePoint)) { + return new StringBuilder().appendCodePoint(codePoint).toString(); + } + // check for illegal characters + if ( ( codePoint <= 0x1f + && codePoint != '\t' + && codePoint != '\n' + && codePoint != '\r' ) + || ( codePoint >= 0x7f && codePoint <= 0x9f ) ) + { + hex = REPLACEMENT_HEX; // Let's entity encode this instead of returning it + codePoint = REPLACEMENT_CHAR; + } + + // check if there's a defined entity + String entityName = characterToEntityMap.get(codePoint); + if (entityName != null) { + return "&" + entityName + ";"; + } + + // return the hex entity as suggested in the spec + return "&#x" + hex + ";"; + } + + /** + * {@inheritDoc} + * + * Returns the decoded version of the character starting at index, or + * null if no decoding is possible. + * + * Formats all are legal both with and without semi-colon, upper/lower case: + * &#dddd; + * &#xhhhh; + * &name; + */ + public Integer decodeCharacter( PushbackSequence input ) { + input.mark(); + Integer first = input.next(); + if ( first == null ) { + input.reset(); + return null; + } + + // if this is not an encoded character, return null + if (first != '&' ) { + input.reset(); + return null; + } + + // test for numeric encodings + Integer second = input.next(); + if ( second == null ) { + input.reset(); + return null; + } + + if (second == '#' ) { + // handle numbers + Integer c = getNumericEntity( input ); + if ( c != null ) return c; + } else if ( Character.isLetter( second ) ) { + // handle entities + input.pushback( second ); + Integer c = getNamedEntity( input ); + if ( c != null ) return c; + } + input.reset(); + return null; + } + + /** + * getNumericEntry checks input to see if it is a numeric entity + * + * @param input + * The input to test for being a numeric entity + * + * @return + * null if input is null, the character of input after decoding + */ + private Integer getNumericEntity( PushbackSequence input ) { + Integer first = input.peek(); + if ( first == null ) return null; - if (first == 'x' || first == 'X' ) { - input.next(); - return parseHex( input ); - } - return parseNumber( input ); - } + if (first == 'x' || first == 'X' ) { + input.next(); + return parseHex( input ); + } + return parseNumber( input ); + } - /** - * Parse a decimal number, such as those from JavaScript's String.fromCharCode(value) - * - * @param input - * decimal encoded string, such as 65 - * @return - * character representation of this decimal value, e.g. A - * @throws NumberFormatException - */ - private Integer parseNumber( PushbackSequence input ) { - StringBuilder sb = new StringBuilder(); - while( input.hasNext() ) { - Integer c = input.peek(); - - // if character is a digit then add it on and keep going - if ( Character.isDigit( c ) && Character.isValidCodePoint(c) ) { - sb.appendCodePoint( c ); - input.next(); - - // if character is a semi-colon, eat it and quit - } else if (c == ';' ) { - input.next(); - break; - - // otherwise just quit - } else { - break; - } - } - try { - int i = Integer.parseInt(sb.toString()); + /** + * Parse a decimal number, such as those from JavaScript's String.fromCharCode(value) + * + * @param input + * decimal encoded string, such as 65 + * @return + * character representation of this decimal value, e.g. A + * @throws NumberFormatException + */ + private Integer parseNumber( PushbackSequence input ) { + StringBuilder sb = new StringBuilder(); + while( input.hasNext() ) { + Integer c = input.peek(); + + // if character is a digit then add it on and keep going + if ( Character.isDigit( c ) && Character.isValidCodePoint(c) ) { + sb.appendCodePoint( c ); + input.next(); + + // if character is a semi-colon, eat it and quit + } else if (c == ';' ) { + input.next(); + break; + + // otherwise just quit + } else { + break; + } + } + try { + int i = Integer.parseInt(sb.toString()); if (Character.isValidCodePoint(i)) { return i; } - } catch( NumberFormatException e ) { - // throw an exception for malformed entity? - } - return null; - } - - /** - * Parse a hex encoded entity - * - * @param input - * Hex encoded input (such as 437ae;) - * @return - * A single character from the string - * @throws NumberFormatException - */ - private Integer parseHex( PushbackSequence input ) { - StringBuilder sb = new StringBuilder(); - while( input.hasNext() ) { - Integer c = input.peek(); - - // if character is a hex digit then add it on and keep going - //This statement implicitly tests for Character.isValidCodePoint(int) - if ( "0123456789ABCDEFabcdef".indexOf(c) != -1 ) { - sb.appendCodePoint( c ); - input.next(); - - // if character is a semi-colon, eat it and quit - } else if (c == ';' ) { - input.next(); - break; - - // otherwise just quit - } else { - break; - } - } - try { - int i = Integer.parseInt(sb.toString(), 16); + } catch( NumberFormatException e ) { + // throw an exception for malformed entity? + } + return null; + } + + /** + * Parse a hex encoded entity + * + * @param input + * Hex encoded input (such as 437ae;) + * @return + * A single character from the string + * @throws NumberFormatException + */ + private Integer parseHex( PushbackSequence input ) { + StringBuilder sb = new StringBuilder(); + while( input.hasNext() ) { + Integer c = input.peek(); + + // if character is a hex digit then add it on and keep going + //This statement implicitly tests for Character.isValidCodePoint(int) + if ( "0123456789ABCDEFabcdef".indexOf(c) != -1 ) { + sb.appendCodePoint( c ); + input.next(); + + // if character is a semi-colon, eat it and quit + } else if (c == ';' ) { + input.next(); + break; + + // otherwise just quit + } else { + break; + } + } + try { + int i = Integer.parseInt(sb.toString(), 16); if (Character.isValidCodePoint(i)) { return i; } - } catch( NumberFormatException e ) { - // throw an exception for malformed entity? - } - return null; - } - - /** - * - * Returns the decoded version of the character starting at index, or - * null if no decoding is possible. - * - * Formats all are legal both with and without semi-colon, upper/lower case: - * &aa; - * &aaa; - * &aaaa; - * &aaaaa; - * &aaaaaa; - * &aaaaaaa; - * - * @param input - * A string containing a named entity like " - * @return - * Returns the decoded version of the character starting at index, or null if no decoding is possible. - */ - private Integer getNamedEntity( PushbackSequence input ) { - StringBuilder possible = new StringBuilder(); - Entry entry; - int len; - - // kludge around PushbackString.... - len = Math.min(input.remainder().length(), entityToCharacterTrie.getMaxKeyLength()); - for(int i=0;i exactEntry = entityToCharacterTrie.getLongestMatch(possibleStringLowerCase); - if(exactEntry != null) entry = exactEntry; - } - if(entry == null) return null; // no match, caller will reset input - } + } catch( NumberFormatException e ) { + // throw an exception for malformed entity? + } + return null; + } + + /** + * + * Returns the decoded version of the character starting at index, or + * null if no decoding is possible. + * + * Formats all are legal both with and without semi-colon, upper/lower case: + * &aa; + * &aaa; + * &aaaa; + * &aaaaa; + * &aaaaaa; + * &aaaaaaa; + * + * @param input + * A string containing a named entity like " + * @return + * Returns the decoded version of the character starting at index, or null if no decoding is possible. + */ + private Integer getNamedEntity( PushbackSequence input ) { + StringBuilder possible = new StringBuilder(); + Entry entry; + int len; + + // kludge around PushbackString.... + len = Math.min(input.remainder().length(), entityToCharacterTrie.getMaxKeyLength()); + for(int i=0;i exactEntry = entityToCharacterTrie.getLongestMatch(possibleStringLowerCase); + if(exactEntry != null) entry = exactEntry; + } + if(entry == null) return null; // no match, caller will reset input + } - // fixup input - input.reset(); - input.next(); // read & - len = entry.getKey().length(); // what matched's length - for(int i=0;i mkCharacterToEntityMap() - { - Map map = new HashMap(252); + /** + * Build a unmodifiable Map from entity Character to Name. + * @return Unmodifiable map. + */ + private static synchronized Map mkCharacterToEntityMap() + { + Map map = new HashMap(252); - map.put(34, "quot"); /* quotation mark */ - map.put(38, "amp"); /* ampersand */ - map.put(60, "lt"); /* less-than sign */ - map.put(62, "gt"); /* greater-than sign */ - map.put(160, "nbsp"); /* no-break space */ - map.put(161, "iexcl"); /* inverted exclamation mark */ - map.put(162, "cent"); /* cent sign */ - map.put(163, "pound"); /* pound sign */ - map.put(164, "curren"); /* currency sign */ - map.put(165, "yen"); /* yen sign */ - map.put(166, "brvbar"); /* broken bar */ - map.put(167, "sect"); /* section sign */ - map.put(168, "uml"); /* diaeresis */ - map.put(169, "copy"); /* copyright sign */ - map.put(170, "ordf"); /* feminine ordinal indicator */ - map.put(171, "laquo"); /* left-pointing double angle quotation mark */ - map.put(172, "not"); /* not sign */ - map.put(173, "shy"); /* soft hyphen */ - map.put(174, "reg"); /* registered sign */ - map.put(175, "macr"); /* macron */ - map.put(176, "deg"); /* degree sign */ - map.put(177, "plusmn"); /* plus-minus sign */ - map.put(178, "sup2"); /* superscript two */ - map.put(179, "sup3"); /* superscript three */ - map.put(180, "acute"); /* acute accent */ - map.put(181, "micro"); /* micro sign */ - map.put(182, "para"); /* pilcrow sign */ - map.put(183, "middot"); /* middle dot */ - map.put(184, "cedil"); /* cedilla */ - map.put(185, "sup1"); /* superscript one */ - map.put(186, "ordm"); /* masculine ordinal indicator */ - map.put(187, "raquo"); /* right-pointing double angle quotation mark */ - map.put(188, "frac14"); /* vulgar fraction one quarter */ - map.put(189, "frac12"); /* vulgar fraction one half */ - map.put(190, "frac34"); /* vulgar fraction three quarters */ - map.put(191, "iquest"); /* inverted question mark */ - map.put(192, "Agrave"); /* Latin capital letter a with grave */ - map.put(193, "Aacute"); /* Latin capital letter a with acute */ - map.put(194, "Acirc"); /* Latin capital letter a with circumflex */ - map.put(195, "Atilde"); /* Latin capital letter a with tilde */ - map.put(196, "Auml"); /* Latin capital letter a with diaeresis */ - map.put(197, "Aring"); /* Latin capital letter a with ring above */ - map.put(198, "AElig"); /* Latin capital letter ae */ - map.put(199, "Ccedil"); /* Latin capital letter c with cedilla */ - map.put(200, "Egrave"); /* Latin capital letter e with grave */ - map.put(201, "Eacute"); /* Latin capital letter e with acute */ - map.put(202, "Ecirc"); /* Latin capital letter e with circumflex */ - map.put(203, "Euml"); /* Latin capital letter e with diaeresis */ - map.put(204, "Igrave"); /* Latin capital letter i with grave */ - map.put(205, "Iacute"); /* Latin capital letter i with acute */ - map.put(206, "Icirc"); /* Latin capital letter i with circumflex */ - map.put(207, "Iuml"); /* Latin capital letter i with diaeresis */ - map.put(208, "ETH"); /* Latin capital letter eth */ - map.put(209, "Ntilde"); /* Latin capital letter n with tilde */ - map.put(210, "Ograve"); /* Latin capital letter o with grave */ - map.put(211, "Oacute"); /* Latin capital letter o with acute */ - map.put(212, "Ocirc"); /* Latin capital letter o with circumflex */ - map.put(213, "Otilde"); /* Latin capital letter o with tilde */ - map.put(214, "Ouml"); /* Latin capital letter o with diaeresis */ - map.put(215, "times"); /* multiplication sign */ - map.put(216, "Oslash"); /* Latin capital letter o with stroke */ - map.put(217, "Ugrave"); /* Latin capital letter u with grave */ - map.put(218, "Uacute"); /* Latin capital letter u with acute */ - map.put(219, "Ucirc"); /* Latin capital letter u with circumflex */ - map.put(220, "Uuml"); /* Latin capital letter u with diaeresis */ - map.put(221, "Yacute"); /* Latin capital letter y with acute */ - map.put(222, "THORN"); /* Latin capital letter thorn */ - map.put(223, "szlig"); /* Latin small letter sharp sXCOMMAX German Eszett */ - map.put(224, "agrave"); /* Latin small letter a with grave */ - map.put(225, "aacute"); /* Latin small letter a with acute */ - map.put(226, "acirc"); /* Latin small letter a with circumflex */ - map.put(227, "atilde"); /* Latin small letter a with tilde */ - map.put(228, "auml"); /* Latin small letter a with diaeresis */ - map.put(229, "aring"); /* Latin small letter a with ring above */ - map.put(230, "aelig"); /* Latin lowercase ligature ae */ - map.put(231, "ccedil"); /* Latin small letter c with cedilla */ - map.put(232, "egrave"); /* Latin small letter e with grave */ - map.put(233, "eacute"); /* Latin small letter e with acute */ - map.put(234, "ecirc"); /* Latin small letter e with circumflex */ - map.put(235, "euml"); /* Latin small letter e with diaeresis */ - map.put(236, "igrave"); /* Latin small letter i with grave */ - map.put(237, "iacute"); /* Latin small letter i with acute */ - map.put(238, "icirc"); /* Latin small letter i with circumflex */ - map.put(239, "iuml"); /* Latin small letter i with diaeresis */ - map.put(240, "eth"); /* Latin small letter eth */ - map.put(241, "ntilde"); /* Latin small letter n with tilde */ - map.put(242, "ograve"); /* Latin small letter o with grave */ - map.put(243, "oacute"); /* Latin small letter o with acute */ - map.put(244, "ocirc"); /* Latin small letter o with circumflex */ - map.put(245, "otilde"); /* Latin small letter o with tilde */ - map.put(246, "ouml"); /* Latin small letter o with diaeresis */ - map.put(247, "divide"); /* division sign */ - map.put(248, "oslash"); /* Latin small letter o with stroke */ - map.put(249, "ugrave"); /* Latin small letter u with grave */ - map.put(250, "uacute"); /* Latin small letter u with acute */ - map.put(251, "ucirc"); /* Latin small letter u with circumflex */ - map.put(252, "uuml"); /* Latin small letter u with diaeresis */ - map.put(253, "yacute"); /* Latin small letter y with acute */ - map.put(254, "thorn"); /* Latin small letter thorn */ - map.put(255, "yuml"); /* Latin small letter y with diaeresis */ - map.put(338, "OElig"); /* Latin capital ligature oe */ - map.put(339, "oelig"); /* Latin small ligature oe */ - map.put(352, "Scaron"); /* Latin capital letter s with caron */ - map.put(353, "scaron"); /* Latin small letter s with caron */ - map.put(376, "Yuml"); /* Latin capital letter y with diaeresis */ - map.put(402, "fnof"); /* Latin small letter f with hook */ - map.put(710, "circ"); /* modifier letter circumflex accent */ - map.put(732, "tilde"); /* small tilde */ - map.put(913, "Alpha"); /* Greek capital letter alpha */ - map.put(914, "Beta"); /* Greek capital letter beta */ - map.put(915, "Gamma"); /* Greek capital letter gamma */ - map.put(916, "Delta"); /* Greek capital letter delta */ - map.put(917, "Epsilon"); /* Greek capital letter epsilon */ - map.put(918, "Zeta"); /* Greek capital letter zeta */ - map.put(919, "Eta"); /* Greek capital letter eta */ - map.put(920, "Theta"); /* Greek capital letter theta */ - map.put(921, "Iota"); /* Greek capital letter iota */ - map.put(922, "Kappa"); /* Greek capital letter kappa */ - map.put(923, "Lambda"); /* Greek capital letter lambda */ - map.put(924, "Mu"); /* Greek capital letter mu */ - map.put(925, "Nu"); /* Greek capital letter nu */ - map.put(926, "Xi"); /* Greek capital letter xi */ - map.put(927, "Omicron"); /* Greek capital letter omicron */ - map.put(928, "Pi"); /* Greek capital letter pi */ - map.put(929, "Rho"); /* Greek capital letter rho */ - map.put(931, "Sigma"); /* Greek capital letter sigma */ - map.put(932, "Tau"); /* Greek capital letter tau */ - map.put(933, "Upsilon"); /* Greek capital letter upsilon */ - map.put(934, "Phi"); /* Greek capital letter phi */ - map.put(935, "Chi"); /* Greek capital letter chi */ - map.put(936, "Psi"); /* Greek capital letter psi */ - map.put(937, "Omega"); /* Greek capital letter omega */ - map.put(945, "alpha"); /* Greek small letter alpha */ - map.put(946, "beta"); /* Greek small letter beta */ - map.put(947, "gamma"); /* Greek small letter gamma */ - map.put(948, "delta"); /* Greek small letter delta */ - map.put(949, "epsilon"); /* Greek small letter epsilon */ - map.put(950, "zeta"); /* Greek small letter zeta */ - map.put(951, "eta"); /* Greek small letter eta */ - map.put(952, "theta"); /* Greek small letter theta */ - map.put(953, "iota"); /* Greek small letter iota */ - map.put(954, "kappa"); /* Greek small letter kappa */ - map.put(955, "lambda"); /* Greek small letter lambda */ - map.put(956, "mu"); /* Greek small letter mu */ - map.put(957, "nu"); /* Greek small letter nu */ - map.put(958, "xi"); /* Greek small letter xi */ - map.put(959, "omicron"); /* Greek small letter omicron */ - map.put(960, "pi"); /* Greek small letter pi */ - map.put(961, "rho"); /* Greek small letter rho */ - map.put(962, "sigmaf"); /* Greek small letter final sigma */ - map.put(963, "sigma"); /* Greek small letter sigma */ - map.put(964, "tau"); /* Greek small letter tau */ - map.put(965, "upsilon"); /* Greek small letter upsilon */ - map.put(966, "phi"); /* Greek small letter phi */ - map.put(967, "chi"); /* Greek small letter chi */ - map.put(968, "psi"); /* Greek small letter psi */ - map.put(969, "omega"); /* Greek small letter omega */ - map.put(977, "thetasym"); /* Greek theta symbol */ - map.put(978, "upsih"); /* Greek upsilon with hook symbol */ - map.put(982, "piv"); /* Greek pi symbol */ - map.put(8194, "ensp"); /* en space */ - map.put(8195, "emsp"); /* em space */ - map.put(8201, "thinsp"); /* thin space */ - map.put(8204, "zwnj"); /* zero width non-joiner */ - map.put(8205, "zwj"); /* zero width joiner */ - map.put(8206, "lrm"); /* left-to-right mark */ - map.put(8207, "rlm"); /* right-to-left mark */ - map.put(8211, "ndash"); /* en dash */ - map.put(8212, "mdash"); /* em dash */ - map.put(8216, "lsquo"); /* left single quotation mark */ - map.put(8217, "rsquo"); /* right single quotation mark */ - map.put(8218, "sbquo"); /* single low-9 quotation mark */ - map.put(8220, "ldquo"); /* left double quotation mark */ - map.put(8221, "rdquo"); /* right double quotation mark */ - map.put(8222, "bdquo"); /* double low-9 quotation mark */ - map.put(8224, "dagger"); /* dagger */ - map.put(8225, "Dagger"); /* double dagger */ - map.put(8226, "bull"); /* bullet */ - map.put(8230, "hellip"); /* horizontal ellipsis */ - map.put(8240, "permil"); /* per mille sign */ - map.put(8242, "prime"); /* prime */ - map.put(8243, "Prime"); /* double prime */ - map.put(8249, "lsaquo"); /* single left-pointing angle quotation mark */ - map.put(8250, "rsaquo"); /* single right-pointing angle quotation mark */ - map.put(8254, "oline"); /* overline */ - map.put(8260, "frasl"); /* fraction slash */ - map.put(8364, "euro"); /* euro sign */ - map.put(8465, "image"); /* black-letter capital i */ - map.put(8472, "weierp"); /* script capital pXCOMMAX Weierstrass p */ - map.put(8476, "real"); /* black-letter capital r */ - map.put(8482, "trade"); /* trademark sign */ - map.put(8501, "alefsym"); /* alef symbol */ - map.put(8592, "larr"); /* leftwards arrow */ - map.put(8593, "uarr"); /* upwards arrow */ - map.put(8594, "rarr"); /* rightwards arrow */ - map.put(8595, "darr"); /* downwards arrow */ - map.put(8596, "harr"); /* left right arrow */ - map.put(8629, "crarr"); /* downwards arrow with corner leftwards */ - map.put(8656, "lArr"); /* leftwards double arrow */ - map.put(8657, "uArr"); /* upwards double arrow */ - map.put(8658, "rArr"); /* rightwards double arrow */ - map.put(8659, "dArr"); /* downwards double arrow */ - map.put(8660, "hArr"); /* left right double arrow */ - map.put(8704, "forall"); /* for all */ - map.put(8706, "part"); /* partial differential */ - map.put(8707, "exist"); /* there exists */ - map.put(8709, "empty"); /* empty set */ - map.put(8711, "nabla"); /* nabla */ - map.put(8712, "isin"); /* element of */ - map.put(8713, "notin"); /* not an element of */ - map.put(8715, "ni"); /* contains as member */ - map.put(8719, "prod"); /* n-ary product */ - map.put(8721, "sum"); /* n-ary summation */ - map.put(8722, "minus"); /* minus sign */ - map.put(8727, "lowast"); /* asterisk operator */ - map.put(8730, "radic"); /* square root */ - map.put(8733, "prop"); /* proportional to */ - map.put(8734, "infin"); /* infinity */ - map.put(8736, "ang"); /* angle */ - map.put(8743, "and"); /* logical and */ - map.put(8744, "or"); /* logical or */ - map.put(8745, "cap"); /* intersection */ - map.put(8746, "cup"); /* union */ - map.put(8747, "int"); /* integral */ - map.put(8756, "there4"); /* therefore */ - map.put(8764, "sim"); /* tilde operator */ - map.put(8773, "cong"); /* congruent to */ - map.put(8776, "asymp"); /* almost equal to */ - map.put(8800, "ne"); /* not equal to */ - map.put(8801, "equiv"); /* identical toXCOMMAX equivalent to */ - map.put(8804, "le"); /* less-than or equal to */ - map.put(8805, "ge"); /* greater-than or equal to */ - map.put(8834, "sub"); /* subset of */ - map.put(8835, "sup"); /* superset of */ - map.put(8836, "nsub"); /* not a subset of */ - map.put(8838, "sube"); /* subset of or equal to */ - map.put(8839, "supe"); /* superset of or equal to */ - map.put(8853, "oplus"); /* circled plus */ - map.put(8855, "otimes"); /* circled times */ - map.put(8869, "perp"); /* up tack */ - map.put(8901, "sdot"); /* dot operator */ - map.put(8968, "lceil"); /* left ceiling */ - map.put(8969, "rceil"); /* right ceiling */ - map.put(8970, "lfloor"); /* left floor */ - map.put(8971, "rfloor"); /* right floor */ - map.put(9001, "lang"); /* left-pointing angle bracket */ - map.put(9002, "rang"); /* right-pointing angle bracket */ - map.put(9674, "loz"); /* lozenge */ - map.put(9824, "spades"); /* black spade suit */ - map.put(9827, "clubs"); /* black club suit */ - map.put(9829, "hearts"); /* black heart suit */ - map.put(9830, "diams"); /* black diamond suit */ + map.put(34, "quot"); /* quotation mark */ + map.put(38, "amp"); /* ampersand */ + map.put(60, "lt"); /* less-than sign */ + map.put(62, "gt"); /* greater-than sign */ + map.put(160, "nbsp"); /* no-break space */ + map.put(161, "iexcl"); /* inverted exclamation mark */ + map.put(162, "cent"); /* cent sign */ + map.put(163, "pound"); /* pound sign */ + map.put(164, "curren"); /* currency sign */ + map.put(165, "yen"); /* yen sign */ + map.put(166, "brvbar"); /* broken bar */ + map.put(167, "sect"); /* section sign */ + map.put(168, "uml"); /* diaeresis */ + map.put(169, "copy"); /* copyright sign */ + map.put(170, "ordf"); /* feminine ordinal indicator */ + map.put(171, "laquo"); /* left-pointing double angle quotation mark */ + map.put(172, "not"); /* not sign */ + map.put(173, "shy"); /* soft hyphen */ + map.put(174, "reg"); /* registered sign */ + map.put(175, "macr"); /* macron */ + map.put(176, "deg"); /* degree sign */ + map.put(177, "plusmn"); /* plus-minus sign */ + map.put(178, "sup2"); /* superscript two */ + map.put(179, "sup3"); /* superscript three */ + map.put(180, "acute"); /* acute accent */ + map.put(181, "micro"); /* micro sign */ + map.put(182, "para"); /* pilcrow sign */ + map.put(183, "middot"); /* middle dot */ + map.put(184, "cedil"); /* cedilla */ + map.put(185, "sup1"); /* superscript one */ + map.put(186, "ordm"); /* masculine ordinal indicator */ + map.put(187, "raquo"); /* right-pointing double angle quotation mark */ + map.put(188, "frac14"); /* vulgar fraction one quarter */ + map.put(189, "frac12"); /* vulgar fraction one half */ + map.put(190, "frac34"); /* vulgar fraction three quarters */ + map.put(191, "iquest"); /* inverted question mark */ + map.put(192, "Agrave"); /* Latin capital letter a with grave */ + map.put(193, "Aacute"); /* Latin capital letter a with acute */ + map.put(194, "Acirc"); /* Latin capital letter a with circumflex */ + map.put(195, "Atilde"); /* Latin capital letter a with tilde */ + map.put(196, "Auml"); /* Latin capital letter a with diaeresis */ + map.put(197, "Aring"); /* Latin capital letter a with ring above */ + map.put(198, "AElig"); /* Latin capital letter ae */ + map.put(199, "Ccedil"); /* Latin capital letter c with cedilla */ + map.put(200, "Egrave"); /* Latin capital letter e with grave */ + map.put(201, "Eacute"); /* Latin capital letter e with acute */ + map.put(202, "Ecirc"); /* Latin capital letter e with circumflex */ + map.put(203, "Euml"); /* Latin capital letter e with diaeresis */ + map.put(204, "Igrave"); /* Latin capital letter i with grave */ + map.put(205, "Iacute"); /* Latin capital letter i with acute */ + map.put(206, "Icirc"); /* Latin capital letter i with circumflex */ + map.put(207, "Iuml"); /* Latin capital letter i with diaeresis */ + map.put(208, "ETH"); /* Latin capital letter eth */ + map.put(209, "Ntilde"); /* Latin capital letter n with tilde */ + map.put(210, "Ograve"); /* Latin capital letter o with grave */ + map.put(211, "Oacute"); /* Latin capital letter o with acute */ + map.put(212, "Ocirc"); /* Latin capital letter o with circumflex */ + map.put(213, "Otilde"); /* Latin capital letter o with tilde */ + map.put(214, "Ouml"); /* Latin capital letter o with diaeresis */ + map.put(215, "times"); /* multiplication sign */ + map.put(216, "Oslash"); /* Latin capital letter o with stroke */ + map.put(217, "Ugrave"); /* Latin capital letter u with grave */ + map.put(218, "Uacute"); /* Latin capital letter u with acute */ + map.put(219, "Ucirc"); /* Latin capital letter u with circumflex */ + map.put(220, "Uuml"); /* Latin capital letter u with diaeresis */ + map.put(221, "Yacute"); /* Latin capital letter y with acute */ + map.put(222, "THORN"); /* Latin capital letter thorn */ + map.put(223, "szlig"); /* Latin small letter sharp sXCOMMAX German Eszett */ + map.put(224, "agrave"); /* Latin small letter a with grave */ + map.put(225, "aacute"); /* Latin small letter a with acute */ + map.put(226, "acirc"); /* Latin small letter a with circumflex */ + map.put(227, "atilde"); /* Latin small letter a with tilde */ + map.put(228, "auml"); /* Latin small letter a with diaeresis */ + map.put(229, "aring"); /* Latin small letter a with ring above */ + map.put(230, "aelig"); /* Latin lowercase ligature ae */ + map.put(231, "ccedil"); /* Latin small letter c with cedilla */ + map.put(232, "egrave"); /* Latin small letter e with grave */ + map.put(233, "eacute"); /* Latin small letter e with acute */ + map.put(234, "ecirc"); /* Latin small letter e with circumflex */ + map.put(235, "euml"); /* Latin small letter e with diaeresis */ + map.put(236, "igrave"); /* Latin small letter i with grave */ + map.put(237, "iacute"); /* Latin small letter i with acute */ + map.put(238, "icirc"); /* Latin small letter i with circumflex */ + map.put(239, "iuml"); /* Latin small letter i with diaeresis */ + map.put(240, "eth"); /* Latin small letter eth */ + map.put(241, "ntilde"); /* Latin small letter n with tilde */ + map.put(242, "ograve"); /* Latin small letter o with grave */ + map.put(243, "oacute"); /* Latin small letter o with acute */ + map.put(244, "ocirc"); /* Latin small letter o with circumflex */ + map.put(245, "otilde"); /* Latin small letter o with tilde */ + map.put(246, "ouml"); /* Latin small letter o with diaeresis */ + map.put(247, "divide"); /* division sign */ + map.put(248, "oslash"); /* Latin small letter o with stroke */ + map.put(249, "ugrave"); /* Latin small letter u with grave */ + map.put(250, "uacute"); /* Latin small letter u with acute */ + map.put(251, "ucirc"); /* Latin small letter u with circumflex */ + map.put(252, "uuml"); /* Latin small letter u with diaeresis */ + map.put(253, "yacute"); /* Latin small letter y with acute */ + map.put(254, "thorn"); /* Latin small letter thorn */ + map.put(255, "yuml"); /* Latin small letter y with diaeresis */ + map.put(338, "OElig"); /* Latin capital ligature oe */ + map.put(339, "oelig"); /* Latin small ligature oe */ + map.put(352, "Scaron"); /* Latin capital letter s with caron */ + map.put(353, "scaron"); /* Latin small letter s with caron */ + map.put(376, "Yuml"); /* Latin capital letter y with diaeresis */ + map.put(402, "fnof"); /* Latin small letter f with hook */ + map.put(710, "circ"); /* modifier letter circumflex accent */ + map.put(732, "tilde"); /* small tilde */ + map.put(913, "Alpha"); /* Greek capital letter alpha */ + map.put(914, "Beta"); /* Greek capital letter beta */ + map.put(915, "Gamma"); /* Greek capital letter gamma */ + map.put(916, "Delta"); /* Greek capital letter delta */ + map.put(917, "Epsilon"); /* Greek capital letter epsilon */ + map.put(918, "Zeta"); /* Greek capital letter zeta */ + map.put(919, "Eta"); /* Greek capital letter eta */ + map.put(920, "Theta"); /* Greek capital letter theta */ + map.put(921, "Iota"); /* Greek capital letter iota */ + map.put(922, "Kappa"); /* Greek capital letter kappa */ + map.put(923, "Lambda"); /* Greek capital letter lambda */ + map.put(924, "Mu"); /* Greek capital letter mu */ + map.put(925, "Nu"); /* Greek capital letter nu */ + map.put(926, "Xi"); /* Greek capital letter xi */ + map.put(927, "Omicron"); /* Greek capital letter omicron */ + map.put(928, "Pi"); /* Greek capital letter pi */ + map.put(929, "Rho"); /* Greek capital letter rho */ + map.put(931, "Sigma"); /* Greek capital letter sigma */ + map.put(932, "Tau"); /* Greek capital letter tau */ + map.put(933, "Upsilon"); /* Greek capital letter upsilon */ + map.put(934, "Phi"); /* Greek capital letter phi */ + map.put(935, "Chi"); /* Greek capital letter chi */ + map.put(936, "Psi"); /* Greek capital letter psi */ + map.put(937, "Omega"); /* Greek capital letter omega */ + map.put(945, "alpha"); /* Greek small letter alpha */ + map.put(946, "beta"); /* Greek small letter beta */ + map.put(947, "gamma"); /* Greek small letter gamma */ + map.put(948, "delta"); /* Greek small letter delta */ + map.put(949, "epsilon"); /* Greek small letter epsilon */ + map.put(950, "zeta"); /* Greek small letter zeta */ + map.put(951, "eta"); /* Greek small letter eta */ + map.put(952, "theta"); /* Greek small letter theta */ + map.put(953, "iota"); /* Greek small letter iota */ + map.put(954, "kappa"); /* Greek small letter kappa */ + map.put(955, "lambda"); /* Greek small letter lambda */ + map.put(956, "mu"); /* Greek small letter mu */ + map.put(957, "nu"); /* Greek small letter nu */ + map.put(958, "xi"); /* Greek small letter xi */ + map.put(959, "omicron"); /* Greek small letter omicron */ + map.put(960, "pi"); /* Greek small letter pi */ + map.put(961, "rho"); /* Greek small letter rho */ + map.put(962, "sigmaf"); /* Greek small letter final sigma */ + map.put(963, "sigma"); /* Greek small letter sigma */ + map.put(964, "tau"); /* Greek small letter tau */ + map.put(965, "upsilon"); /* Greek small letter upsilon */ + map.put(966, "phi"); /* Greek small letter phi */ + map.put(967, "chi"); /* Greek small letter chi */ + map.put(968, "psi"); /* Greek small letter psi */ + map.put(969, "omega"); /* Greek small letter omega */ + map.put(977, "thetasym"); /* Greek theta symbol */ + map.put(978, "upsih"); /* Greek upsilon with hook symbol */ + map.put(982, "piv"); /* Greek pi symbol */ + map.put(8194, "ensp"); /* en space */ + map.put(8195, "emsp"); /* em space */ + map.put(8201, "thinsp"); /* thin space */ + map.put(8204, "zwnj"); /* zero width non-joiner */ + map.put(8205, "zwj"); /* zero width joiner */ + map.put(8206, "lrm"); /* left-to-right mark */ + map.put(8207, "rlm"); /* right-to-left mark */ + map.put(8211, "ndash"); /* en dash */ + map.put(8212, "mdash"); /* em dash */ + map.put(8216, "lsquo"); /* left single quotation mark */ + map.put(8217, "rsquo"); /* right single quotation mark */ + map.put(8218, "sbquo"); /* single low-9 quotation mark */ + map.put(8220, "ldquo"); /* left double quotation mark */ + map.put(8221, "rdquo"); /* right double quotation mark */ + map.put(8222, "bdquo"); /* double low-9 quotation mark */ + map.put(8224, "dagger"); /* dagger */ + map.put(8225, "Dagger"); /* double dagger */ + map.put(8226, "bull"); /* bullet */ + map.put(8230, "hellip"); /* horizontal ellipsis */ + map.put(8240, "permil"); /* per mille sign */ + map.put(8242, "prime"); /* prime */ + map.put(8243, "Prime"); /* double prime */ + map.put(8249, "lsaquo"); /* single left-pointing angle quotation mark */ + map.put(8250, "rsaquo"); /* single right-pointing angle quotation mark */ + map.put(8254, "oline"); /* overline */ + map.put(8260, "frasl"); /* fraction slash */ + map.put(8364, "euro"); /* euro sign */ + map.put(8465, "image"); /* black-letter capital i */ + map.put(8472, "weierp"); /* script capital pXCOMMAX Weierstrass p */ + map.put(8476, "real"); /* black-letter capital r */ + map.put(8482, "trade"); /* trademark sign */ + map.put(8501, "alefsym"); /* alef symbol */ + map.put(8592, "larr"); /* leftwards arrow */ + map.put(8593, "uarr"); /* upwards arrow */ + map.put(8594, "rarr"); /* rightwards arrow */ + map.put(8595, "darr"); /* downwards arrow */ + map.put(8596, "harr"); /* left right arrow */ + map.put(8629, "crarr"); /* downwards arrow with corner leftwards */ + map.put(8656, "lArr"); /* leftwards double arrow */ + map.put(8657, "uArr"); /* upwards double arrow */ + map.put(8658, "rArr"); /* rightwards double arrow */ + map.put(8659, "dArr"); /* downwards double arrow */ + map.put(8660, "hArr"); /* left right double arrow */ + map.put(8704, "forall"); /* for all */ + map.put(8706, "part"); /* partial differential */ + map.put(8707, "exist"); /* there exists */ + map.put(8709, "empty"); /* empty set */ + map.put(8711, "nabla"); /* nabla */ + map.put(8712, "isin"); /* element of */ + map.put(8713, "notin"); /* not an element of */ + map.put(8715, "ni"); /* contains as member */ + map.put(8719, "prod"); /* n-ary product */ + map.put(8721, "sum"); /* n-ary summation */ + map.put(8722, "minus"); /* minus sign */ + map.put(8727, "lowast"); /* asterisk operator */ + map.put(8730, "radic"); /* square root */ + map.put(8733, "prop"); /* proportional to */ + map.put(8734, "infin"); /* infinity */ + map.put(8736, "ang"); /* angle */ + map.put(8743, "and"); /* logical and */ + map.put(8744, "or"); /* logical or */ + map.put(8745, "cap"); /* intersection */ + map.put(8746, "cup"); /* union */ + map.put(8747, "int"); /* integral */ + map.put(8756, "there4"); /* therefore */ + map.put(8764, "sim"); /* tilde operator */ + map.put(8773, "cong"); /* congruent to */ + map.put(8776, "asymp"); /* almost equal to */ + map.put(8800, "ne"); /* not equal to */ + map.put(8801, "equiv"); /* identical toXCOMMAX equivalent to */ + map.put(8804, "le"); /* less-than or equal to */ + map.put(8805, "ge"); /* greater-than or equal to */ + map.put(8834, "sub"); /* subset of */ + map.put(8835, "sup"); /* superset of */ + map.put(8836, "nsub"); /* not a subset of */ + map.put(8838, "sube"); /* subset of or equal to */ + map.put(8839, "supe"); /* superset of or equal to */ + map.put(8853, "oplus"); /* circled plus */ + map.put(8855, "otimes"); /* circled times */ + map.put(8869, "perp"); /* up tack */ + map.put(8901, "sdot"); /* dot operator */ + map.put(8968, "lceil"); /* left ceiling */ + map.put(8969, "rceil"); /* right ceiling */ + map.put(8970, "lfloor"); /* left floor */ + map.put(8971, "rfloor"); /* right floor */ + map.put(9001, "lang"); /* left-pointing angle bracket */ + map.put(9002, "rang"); /* right-pointing angle bracket */ + map.put(9674, "loz"); /* lozenge */ + map.put(9824, "spades"); /* black spade suit */ + map.put(9827, "clubs"); /* black club suit */ + map.put(9829, "hearts"); /* black heart suit */ + map.put(9830, "diams"); /* black diamond suit */ - return Collections.unmodifiableMap(map); - } + return Collections.unmodifiableMap(map); + } - /** - * Build a unmodifiable Trie from entitiy Name to Character - * @return Unmodifiable trie. - */ - private static synchronized Trie mkEntityToCharacterTrie() - { - Trie trie = new HashTrie(); + /** + * Build a unmodifiable Trie from entitiy Name to Character + * @return Unmodifiable trie. + */ + private static synchronized Trie mkEntityToCharacterTrie() + { + Trie trie = new HashTrie(); - for(Map.Entry entry : characterToEntityMap.entrySet()) - trie.put(entry.getValue(),entry.getKey()); - return Trie.Util.unmodifiable(trie); - } + for(Map.Entry entry : characterToEntityMap.entrySet()) + trie.put(entry.getValue(),entry.getKey()); + return Trie.Util.unmodifiable(trie); + } } diff --git a/src/main/java/org/owasp/esapi/codecs/HashTrie.java b/src/main/java/org/owasp/esapi/codecs/HashTrie.java index fef14aee7..9c5829410 100644 --- a/src/main/java/org/owasp/esapi/codecs/HashTrie.java +++ b/src/main/java/org/owasp/esapi/codecs/HashTrie.java @@ -18,591 +18,591 @@ * * NOTE:
    *
      - *
    • @see java.util.Map.remove(Object) is not supported.
    • - *
    • - * If deletion support is added, the max key length will need work or removal. - *
    • - *
    • Null values are not supported.
    • + *
    • @see java.util.Map.remove(Object) is not supported.
    • + *
    • + * If deletion support is added, the max key length will need work or removal. + *
    • + *
    • Null values are not supported.
    • *
    * * @author Ed Schaller */ public class HashTrie implements Trie { - private static class Entry implements Map.Entry - { - private CharSequence key; - private T value; - - Entry(CharSequence key, T value) - { - this.key = key; - this.value = value; - } - - /** - * Convenience instantiator. - * @param key The key for the new instance - * @param keyLength The length of the key to use - * @param value The value for the new instance - * @return null if key or value is null - * new Entry(key,value) if {@link CharSequence#length()} == keyLength - * new Entry(key.subSequence(0,keyLength),value) otherwise - */ - static Entry newInstanceIfNeeded(CharSequence key, int keyLength, T value) - { - if(value == null || key == null) - return null; - if(key.length() > keyLength) - key = key.subSequence(0,keyLength); - return new Entry(key,value); - } - - /** - * Convenience instantiator. - * @param key The key for the new instance - * @param value The value for the new instance - * @return null if key or value is null - * new Entry(key,value) otherwise - */ - static Entry newInstanceIfNeeded(CharSequence key, T value) - { - if(value == null || key == null) - return null; - return new Entry(key,value); - } + private static class Entry implements Map.Entry + { + private CharSequence key; + private T value; + + Entry(CharSequence key, T value) + { + this.key = key; + this.value = value; + } + + /** + * Convenience instantiator. + * @param key The key for the new instance + * @param keyLength The length of the key to use + * @param value The value for the new instance + * @return null if key or value is null + * new Entry(key,value) if {@link CharSequence#length()} == keyLength + * new Entry(key.subSequence(0,keyLength),value) otherwise + */ + static Entry newInstanceIfNeeded(CharSequence key, int keyLength, T value) + { + if(value == null || key == null) + return null; + if(key.length() > keyLength) + key = key.subSequence(0,keyLength); + return new Entry(key,value); + } + + /** + * Convenience instantiator. + * @param key The key for the new instance + * @param value The value for the new instance + * @return null if key or value is null + * new Entry(key,value) otherwise + */ + static Entry newInstanceIfNeeded(CharSequence key, T value) + { + if(value == null || key == null) + return null; + return new Entry(key,value); + } /*************/ /* Map.Entry */ /*************/ - public CharSequence getKey() - { - return key; - } + public CharSequence getKey() + { + return key; + } - public T getValue() - { - return value; - } + public T getValue() + { + return value; + } - public T setValue(T value) - { - throw new UnsupportedOperationException(); - } + public T setValue(T value) + { + throw new UnsupportedOperationException(); + } /********************/ /* java.lang.Object */ /********************/ - public boolean equals(Map.Entry other) - { - return (NullSafe.equals(key, other.getKey()) && NullSafe.equals(value, other.getValue())); - } - - @Override - public boolean equals(Object o) - { - if(o instanceof Map.Entry) - return equals((Map.Entry)o); - return false; - } - - @Override - public int hashCode() - { - return NullSafe.hashCode(key) ^ NullSafe.hashCode(value); - } - - @Override - public String toString() - { - return NullSafe.toString(key) + " => " + NullSafe.toString(value); - } - } - - /** - * Node inside the trie. - */ - private static class Node - { - private T value = null; - private Map> nextMap; - - /** - * Create a new Map for a node level. This is here so - * that if the underlying * Map implementation needs to - * be switched it is easily done. - * @return A new Map for use. - */ - private static Map> newNodeMap() - { - return new HashMap>(); - } - - /** - * Create a new Map for a node level. This is here so - * that if the underlying * Map implementation needs to - * be switched it is easily done. - * @param prev Previous map to use to populate the - * new map. - * @return A new Map for use. - */ - private static Map> newNodeMap(Map> prev) - { - return new HashMap>(prev); - } - - /** - * Set the value for the key terminated at this node. - * @param value The value for this key. - */ - void setValue(T value) - { - this.value = value; - } - - /** - * Get the node for the specified character. - * @param ch The next character to look for. - * @return The node requested or null if it is not - * present. - */ - Node getNextNode(Character ch) - { - if(nextMap == null) - return null; - return nextMap.get(ch); - } - - /** - * Recursively add a key. - * @param key The key being added. - * @param pos The position in key that is being handled - * at this level. - */ - T put(CharSequence key, int pos, T addValue) - { - Node nextNode; - Character ch; - T old; - - if(key.length() == pos) - { // at terminating node - old = value; - setValue(addValue); - return old; - } - ch = key.charAt(pos); - if(nextMap == null) - { - nextMap = newNodeMap(); - nextNode = new Node(); - nextMap.put(ch, nextNode); - } - else if((nextNode = nextMap.get(ch))==null) - { - nextNode = new Node(); - nextMap.put(ch,nextNode); - } - return nextNode.put(key,pos+1,addValue); - } - - /** - * Recursively lookup a key's value. - * @param key The key being looked up. - * @param pos The position in the key that is being - * looked up at this level. - * @return The value associated with the key or null if none exists. - */ - T get(CharSequence key, int pos) - { - Node nextNode; - - if(key.length() <= pos) // <= instead of == just in case - return value; // no value is null which is also not found - if((nextNode = getNextNode(key.charAt(pos)))==null) - return null; - return nextNode.get(key,pos+1); - } - - /** - * Recursively lookup the longest key match. - * @param key The key being looked up. - * @param pos The position in the key that is being - * looked up at this level. - * @return The Entry associated with the longest key match or null if none exists. - */ - Entry getLongestMatch(CharSequence key, int pos) - { - Node nextNode; - Entry ret; - - if(key.length() <= pos) // <= instead of == just in case - return Entry.newInstanceIfNeeded(key,value); - if((nextNode = getNextNode(key.charAt(pos)))==null) - { // last in trie... return ourselves - return Entry.newInstanceIfNeeded(key,pos,value); - } - if((ret = nextNode.getLongestMatch(key, pos+1))!=null) - return ret; - return Entry.newInstanceIfNeeded(key,pos,value); - } - - /** - * Recursively lookup the longest key match. - * @param keyIn Where to read the key from - * @param key The key that is being looked up at this level. - * @return The Entry associated with the longest key - * match or null if none exists. - */ - Entry getLongestMatch(PushbackReader keyIn, StringBuilder key) throws IOException - { - Node nextNode; - Entry ret; - int c; - char ch; - int prevLen; - - // read next key char and append to key... - if((c = keyIn.read())<0) - // end of input, return what we have currently - return Entry.newInstanceIfNeeded(key,value); - ch = (char)c; - prevLen = key.length(); - key.append(ch); - - if((nextNode = getNextNode(ch))==null) - { // last in trie... return ourselves - return Entry.newInstanceIfNeeded(key,value); - } - if((ret = nextNode.getLongestMatch(keyIn, key))!=null) - return ret; - - // undo reading of key char and appending to key... - key.setLength(prevLen); - keyIn.unread(c); - - return Entry.newInstanceIfNeeded(key,value); - } - - /** - * Recursively rebuild the internal maps. - */ - void remap() - { - if(nextMap == null) - return; - nextMap = newNodeMap(nextMap); - for(Node node : nextMap.values()) - node.remap(); - } - - /** - * Recursively search for a value. - * @param toFind The value to search for - * @return true if the value was found - * false otherwise - */ - boolean containsValue(Object toFind) - { - if(value != null && toFind.equals(value)) - return true; - if(nextMap == null) - return false; - for(Node node : nextMap.values()) - if(node.containsValue(toFind)) - return true; - return false; - } - - /** - * Recursively build values. - * @param values List being built. - * @return true if the value was found - * false otherwise - */ - Collection values(Collection values) - { - if(value != null) - values.add(value); - if(nextMap == null) - return values; - for(Node node : nextMap.values()) - node.values(values); - return values; - } - - /** - * Recursively build a key set. - * @param key StringBuilder with our key. - * @param keys Set to add to - * @return keys with additions - */ - Set keySet(StringBuilder key, Set keys) - { - int len = key.length(); - - if(value != null) - // MUST toString here - keys.add(key.toString()); - if(nextMap != null && nextMap.size() > 0) - { - key.append('X'); - for(Map.Entry> entry : nextMap.entrySet()) - { - key.setCharAt(len,entry.getKey()); - entry.getValue().keySet(key,keys); - } - key.setLength(len); - } - return keys; - } - - /** - * Recursively build a entry set. - * @param key StringBuilder with our key. - * @param entries Set to add to - * @return entries with additions - */ - Set> entrySet(StringBuilder key, Set> entries) - { - int len = key.length(); - - if(value != null) - // MUST toString here - entries.add(new Entry(key.toString(),value)); - if(nextMap != null && nextMap.size() > 0) - { - key.append('X'); - for(Map.Entry> entry : nextMap.entrySet()) - { - key.setCharAt(len,entry.getKey()); - entry.getValue().entrySet(key,entries); - } - key.setLength(len); - } - return entries; - } - } - - private Node root; - private int maxKeyLen; - private int size; - - public HashTrie() - { - clear(); - } - - /** - * Get the key value entry who's key is the longest prefix match. - * @param key The key to lookup - * @return Entry with the longest matching key. - */ - public Map.Entry getLongestMatch(CharSequence key) - { - if(root == null || key == null) - return null; - return root.getLongestMatch(key, 0); - } - - /** - * Get the key value entry who's key is the longest prefix match. - * @param keyIn Pushback reader to read the key from. This should - * have a buffer at least as large as {@link #getMaxKeyLength()} - * or an IOException may be thrown backing up. - * @return Entry with the longest matching key. - * @throws IOException if keyIn.read() or keyIn.unread() does. - */ - public Map.Entry getLongestMatch(PushbackReader keyIn) throws IOException - { - if(root == null || keyIn == null) - return null; - return root.getLongestMatch(keyIn, new StringBuilder()); - } - - /** - * Get the maximum key length. - * @return max key length. - */ - public int getMaxKeyLength() - { - return maxKeyLen; - } + public boolean equals(Map.Entry other) + { + return (NullSafe.equals(key, other.getKey()) && NullSafe.equals(value, other.getValue())); + } + + @Override + public boolean equals(Object o) + { + if(o instanceof Map.Entry) + return equals((Map.Entry)o); + return false; + } + + @Override + public int hashCode() + { + return NullSafe.hashCode(key) ^ NullSafe.hashCode(value); + } + + @Override + public String toString() + { + return NullSafe.toString(key) + " => " + NullSafe.toString(value); + } + } + + /** + * Node inside the trie. + */ + private static class Node + { + private T value = null; + private Map> nextMap; + + /** + * Create a new Map for a node level. This is here so + * that if the underlying * Map implementation needs to + * be switched it is easily done. + * @return A new Map for use. + */ + private static Map> newNodeMap() + { + return new HashMap>(); + } + + /** + * Create a new Map for a node level. This is here so + * that if the underlying * Map implementation needs to + * be switched it is easily done. + * @param prev Previous map to use to populate the + * new map. + * @return A new Map for use. + */ + private static Map> newNodeMap(Map> prev) + { + return new HashMap>(prev); + } + + /** + * Set the value for the key terminated at this node. + * @param value The value for this key. + */ + void setValue(T value) + { + this.value = value; + } + + /** + * Get the node for the specified character. + * @param ch The next character to look for. + * @return The node requested or null if it is not + * present. + */ + Node getNextNode(Character ch) + { + if(nextMap == null) + return null; + return nextMap.get(ch); + } + + /** + * Recursively add a key. + * @param key The key being added. + * @param pos The position in key that is being handled + * at this level. + */ + T put(CharSequence key, int pos, T addValue) + { + Node nextNode; + Character ch; + T old; + + if(key.length() == pos) + { // at terminating node + old = value; + setValue(addValue); + return old; + } + ch = key.charAt(pos); + if(nextMap == null) + { + nextMap = newNodeMap(); + nextNode = new Node(); + nextMap.put(ch, nextNode); + } + else if((nextNode = nextMap.get(ch))==null) + { + nextNode = new Node(); + nextMap.put(ch,nextNode); + } + return nextNode.put(key,pos+1,addValue); + } + + /** + * Recursively lookup a key's value. + * @param key The key being looked up. + * @param pos The position in the key that is being + * looked up at this level. + * @return The value associated with the key or null if none exists. + */ + T get(CharSequence key, int pos) + { + Node nextNode; + + if(key.length() <= pos) // <= instead of == just in case + return value; // no value is null which is also not found + if((nextNode = getNextNode(key.charAt(pos)))==null) + return null; + return nextNode.get(key,pos+1); + } + + /** + * Recursively lookup the longest key match. + * @param key The key being looked up. + * @param pos The position in the key that is being + * looked up at this level. + * @return The Entry associated with the longest key match or null if none exists. + */ + Entry getLongestMatch(CharSequence key, int pos) + { + Node nextNode; + Entry ret; + + if(key.length() <= pos) // <= instead of == just in case + return Entry.newInstanceIfNeeded(key,value); + if((nextNode = getNextNode(key.charAt(pos)))==null) + { // last in trie... return ourselves + return Entry.newInstanceIfNeeded(key,pos,value); + } + if((ret = nextNode.getLongestMatch(key, pos+1))!=null) + return ret; + return Entry.newInstanceIfNeeded(key,pos,value); + } + + /** + * Recursively lookup the longest key match. + * @param keyIn Where to read the key from + * @param key The key that is being looked up at this level. + * @return The Entry associated with the longest key + * match or null if none exists. + */ + Entry getLongestMatch(PushbackReader keyIn, StringBuilder key) throws IOException + { + Node nextNode; + Entry ret; + int c; + char ch; + int prevLen; + + // read next key char and append to key... + if((c = keyIn.read())<0) + // end of input, return what we have currently + return Entry.newInstanceIfNeeded(key,value); + ch = (char)c; + prevLen = key.length(); + key.append(ch); + + if((nextNode = getNextNode(ch))==null) + { // last in trie... return ourselves + return Entry.newInstanceIfNeeded(key,value); + } + if((ret = nextNode.getLongestMatch(keyIn, key))!=null) + return ret; + + // undo reading of key char and appending to key... + key.setLength(prevLen); + keyIn.unread(c); + + return Entry.newInstanceIfNeeded(key,value); + } + + /** + * Recursively rebuild the internal maps. + */ + void remap() + { + if(nextMap == null) + return; + nextMap = newNodeMap(nextMap); + for(Node node : nextMap.values()) + node.remap(); + } + + /** + * Recursively search for a value. + * @param toFind The value to search for + * @return true if the value was found + * false otherwise + */ + boolean containsValue(Object toFind) + { + if(value != null && toFind.equals(value)) + return true; + if(nextMap == null) + return false; + for(Node node : nextMap.values()) + if(node.containsValue(toFind)) + return true; + return false; + } + + /** + * Recursively build values. + * @param values List being built. + * @return true if the value was found + * false otherwise + */ + Collection values(Collection values) + { + if(value != null) + values.add(value); + if(nextMap == null) + return values; + for(Node node : nextMap.values()) + node.values(values); + return values; + } + + /** + * Recursively build a key set. + * @param key StringBuilder with our key. + * @param keys Set to add to + * @return keys with additions + */ + Set keySet(StringBuilder key, Set keys) + { + int len = key.length(); + + if(value != null) + // MUST toString here + keys.add(key.toString()); + if(nextMap != null && nextMap.size() > 0) + { + key.append('X'); + for(Map.Entry> entry : nextMap.entrySet()) + { + key.setCharAt(len,entry.getKey()); + entry.getValue().keySet(key,keys); + } + key.setLength(len); + } + return keys; + } + + /** + * Recursively build a entry set. + * @param key StringBuilder with our key. + * @param entries Set to add to + * @return entries with additions + */ + Set> entrySet(StringBuilder key, Set> entries) + { + int len = key.length(); + + if(value != null) + // MUST toString here + entries.add(new Entry(key.toString(),value)); + if(nextMap != null && nextMap.size() > 0) + { + key.append('X'); + for(Map.Entry> entry : nextMap.entrySet()) + { + key.setCharAt(len,entry.getKey()); + entry.getValue().entrySet(key,entries); + } + key.setLength(len); + } + return entries; + } + } + + private Node root; + private int maxKeyLen; + private int size; + + public HashTrie() + { + clear(); + } + + /** + * Get the key value entry who's key is the longest prefix match. + * @param key The key to lookup + * @return Entry with the longest matching key. + */ + public Map.Entry getLongestMatch(CharSequence key) + { + if(root == null || key == null) + return null; + return root.getLongestMatch(key, 0); + } + + /** + * Get the key value entry who's key is the longest prefix match. + * @param keyIn Pushback reader to read the key from. This should + * have a buffer at least as large as {@link #getMaxKeyLength()} + * or an IOException may be thrown backing up. + * @return Entry with the longest matching key. + * @throws IOException if keyIn.read() or keyIn.unread() does. + */ + public Map.Entry getLongestMatch(PushbackReader keyIn) throws IOException + { + if(root == null || keyIn == null) + return null; + return root.getLongestMatch(keyIn, new StringBuilder()); + } + + /** + * Get the maximum key length. + * @return max key length. + */ + public int getMaxKeyLength() + { + return maxKeyLen; + } /*****************/ /* java.util.Map */ /*****************/ - /** - * Clear all entries. - */ - public void clear() - { - root = null; - maxKeyLen = -1; - size = 0; - } - - /** {@inheritDoc} */ - public boolean containsKey(Object key) - { - return (get(key) != null); - } - - /** {@inheritDoc} */ - public boolean containsValue(Object value) - { - if(root == null) - return false; - return root.containsValue(value); - } - - /** - * Add mapping. - * @param key The mapping's key. - * @value value The mapping's value - * @throws NullPointerException if key or value is null. - */ - public T put(CharSequence key, T value) throws NullPointerException - { - int len; - T old; - - if(key == null) - throw new NullPointerException("Null keys are not handled"); - if(value == null) - throw new NullPointerException("Null values are not handled"); - if(root == null) - root = new Node(); - if((old = root.put(key,0,value))!=null) - return old; - - // after in case of replacement - if((len = key.length()) > maxKeyLen) - maxKeyLen = len; - size++; - return null; - } - - /** - * Remove a entry. - * @return previous value - * @throws UnsupportedOperationException always. - */ - public T remove(Object key) throws UnsupportedOperationException - { - throw new UnsupportedOperationException(); - } - - /** {@inheritDoc} */ - public void putAll(Map map) - { - for(Map.Entry entry : map.entrySet()) - put(entry.getKey(),entry.getValue()); - } - - /** {@inheritDoc} */ - public Set keySet() - { - Set keys = new HashSet(size); - - if(root == null) - return keys; - return root.keySet(new StringBuilder(), keys); - } - - /** {@inheritDoc} */ - public Collection values() - { - ArrayList values = new ArrayList(size()); - - if(root == null) - return values; - return root.values(values); - } - - /** {@inheritDoc} */ - public Set> entrySet() - { - Set> entries = new HashSet>(size()); - - if(root == null) - return entries; - return root.entrySet(new StringBuilder(), entries); - } - - /** - * Get the value for a key. - * @param key The key to look up. - * @return The value for key or null if the key is not found. - */ - public T get(Object key) - { - if(root == null || key == null) - return null; - if(!(key instanceof CharSequence)) - return null; - return root.get((CharSequence)key,0); - } - - /** - * Get the number of entries. - * @return the number or entries. - */ - public int size() - { - return size; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) - { - if(other == null) - return false; - if(!(other instanceof Map)) - return false; - // per spec - return entrySet().equals(((Map)other).entrySet()); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() - { - // per spec - return entrySet().hashCode(); - } - - /** {@inheritDoc} */ - @Override - public String toString() - { - StringBuilder sb; - boolean first; - - if(isEmpty()) - return "{}"; - sb = new StringBuilder(); - first = true; - sb.append("{ "); - for(Map.Entry entry : entrySet()) - { - if(first) - first = false; - else - sb.append(", "); - sb.append(entry.toString()); - } - sb.append(" }"); - return sb.toString(); - } - - /** {@inheritDoc} */ - public boolean isEmpty() - { - return(size() == 0); - } + /** + * Clear all entries. + */ + public void clear() + { + root = null; + maxKeyLen = -1; + size = 0; + } + + /** {@inheritDoc} */ + public boolean containsKey(Object key) + { + return (get(key) != null); + } + + /** {@inheritDoc} */ + public boolean containsValue(Object value) + { + if(root == null) + return false; + return root.containsValue(value); + } + + /** + * Add mapping. + * @param key The mapping's key. + * @value value The mapping's value + * @throws NullPointerException if key or value is null. + */ + public T put(CharSequence key, T value) throws NullPointerException + { + int len; + T old; + + if(key == null) + throw new NullPointerException("Null keys are not handled"); + if(value == null) + throw new NullPointerException("Null values are not handled"); + if(root == null) + root = new Node(); + if((old = root.put(key,0,value))!=null) + return old; + + // after in case of replacement + if((len = key.length()) > maxKeyLen) + maxKeyLen = len; + size++; + return null; + } + + /** + * Remove a entry. + * @return previous value + * @throws UnsupportedOperationException always. + */ + public T remove(Object key) throws UnsupportedOperationException + { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public void putAll(Map map) + { + for(Map.Entry entry : map.entrySet()) + put(entry.getKey(),entry.getValue()); + } + + /** {@inheritDoc} */ + public Set keySet() + { + Set keys = new HashSet(size); + + if(root == null) + return keys; + return root.keySet(new StringBuilder(), keys); + } + + /** {@inheritDoc} */ + public Collection values() + { + ArrayList values = new ArrayList(size()); + + if(root == null) + return values; + return root.values(values); + } + + /** {@inheritDoc} */ + public Set> entrySet() + { + Set> entries = new HashSet>(size()); + + if(root == null) + return entries; + return root.entrySet(new StringBuilder(), entries); + } + + /** + * Get the value for a key. + * @param key The key to look up. + * @return The value for key or null if the key is not found. + */ + public T get(Object key) + { + if(root == null || key == null) + return null; + if(!(key instanceof CharSequence)) + return null; + return root.get((CharSequence)key,0); + } + + /** + * Get the number of entries. + * @return the number or entries. + */ + public int size() + { + return size; + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object other) + { + if(other == null) + return false; + if(!(other instanceof Map)) + return false; + // per spec + return entrySet().equals(((Map)other).entrySet()); + } + + /** {@inheritDoc} */ + @Override + public int hashCode() + { + // per spec + return entrySet().hashCode(); + } + + /** {@inheritDoc} */ + @Override + public String toString() + { + StringBuilder sb; + boolean first; + + if(isEmpty()) + return "{}"; + sb = new StringBuilder(); + first = true; + sb.append("{ "); + for(Map.Entry entry : entrySet()) + { + if(first) + first = false; + else + sb.append(", "); + sb.append(entry.toString()); + } + sb.append(" }"); + return sb.toString(); + } + + /** {@inheritDoc} */ + public boolean isEmpty() + { + return(size() == 0); + } } diff --git a/src/main/java/org/owasp/esapi/codecs/Hex.java b/src/main/java/org/owasp/esapi/codecs/Hex.java index 17ab4bf52..63b96e932 100644 --- a/src/main/java/org/owasp/esapi/codecs/Hex.java +++ b/src/main/java/org/owasp/esapi/codecs/Hex.java @@ -14,9 +14,9 @@ public class Hex { /** Output byte representation as hexadecimal representation. * - * @param b Bytes to encode to hexadecimal representation. - * @param leading0x If true, return with leading "0x". - * @return Hexadecimal representation of specified bytes. + * @param b Bytes to encode to hexadecimal representation. + * @param leading0x If true, return with leading "0x". + * @return Hexadecimal representation of specified bytes. */ public static String toHex(byte[] b, boolean leading0x) { StringBuffer hexString = new StringBuffer(); @@ -38,9 +38,9 @@ public static String toHex(byte[] b, boolean leading0x) { * Output byte representation as hexadecimal representation. * Alias for toHex() method. * - * @param b Bytes to encode to hexadecimal representation. - * @param leading0x If true, return with leading "0x". - * @return Hexadecimal representation of specified bytes. + * @param b Bytes to encode to hexadecimal representation. + * @param leading0x If true, return with leading "0x". + * @return Hexadecimal representation of specified bytes. */ public static String encode(byte[] b, boolean leading0x) { return toHex(b, leading0x); @@ -54,8 +54,8 @@ public static String encode(byte[] b, boolean leading0x) { * example, the string "0x0000face" is going to return a byte array * whose length is 4, not 2. * - * @param hexStr Hexadecimal-encoded string, with or without leading "0x". - * @return The equivalent byte array. + * @param hexStr Hexadecimal-encoded string, with or without leading "0x". + * @return The equivalent byte array. */ public static byte[] fromHex(String hexStr) { String hexRep = hexStr; @@ -75,8 +75,8 @@ public static byte[] fromHex(String hexStr) { /** Decode hexadecimal-encoded string and return raw byte array. * Alias for fromHex() method. * - * @param hexStr Hexadecimal-encoded string, with or without leading "0x". - * @return The equivalent byte array. + * @param hexStr Hexadecimal-encoded string, with or without leading "0x". + * @return The equivalent byte array. */ public static byte[] decode(String hexStr) { return fromHex(hexStr); diff --git a/src/main/java/org/owasp/esapi/codecs/JavaScriptCodec.java b/src/main/java/org/owasp/esapi/codecs/JavaScriptCodec.java index 65ee517a7..87963cdb6 100644 --- a/src/main/java/org/owasp/esapi/codecs/JavaScriptCodec.java +++ b/src/main/java/org/owasp/esapi/codecs/JavaScriptCodec.java @@ -27,192 +27,192 @@ public class JavaScriptCodec extends AbstractCharacterCodec { - /** - * {@inheritDoc} - * - * Returns backslash encoded numeric format. Does not use backslash character escapes - * such as, \" or \' as these may cause parsing problems. For example, if a javascript - * attribute, such as onmouseover, contains a \" that will close the entire attribute and - * allow an attacker to inject another script attribute. + /** + * {@inheritDoc} + * + * Returns backslash encoded numeric format. Does not use backslash character escapes + * such as, \" or \' as these may cause parsing problems. For example, if a javascript + * attribute, such as onmouseover, contains a \" that will close the entire attribute and + * allow an attacker to inject another script attribute. * * @param immune */ - public String encodeCharacter( char[] immune, Character c ) { + public String encodeCharacter( char[] immune, Character c ) { - // check for immune characters - if ( containsCharacter(c, immune ) ) { - return ""+c; - } - - // check for alphanumeric characters - String hex = super.getHexForNonAlphanumeric(c); - if ( hex == null ) { - return ""+c; - } - - // Do not use these shortcuts as they can be used to break out of a context - // if ( ch == 0x00 ) return "\\0"; - // if ( ch == 0x08 ) return "\\b"; - // if ( ch == 0x09 ) return "\\t"; - // if ( ch == 0x0a ) return "\\n"; - // if ( ch == 0x0b ) return "\\v"; - // if ( ch == 0x0c ) return "\\f"; - // if ( ch == 0x0d ) return "\\r"; - // if ( ch == 0x22 ) return "\\\""; - // if ( ch == 0x27 ) return "\\'"; - // if ( ch == 0x5c ) return "\\\\"; + // check for immune characters + if ( containsCharacter(c, immune ) ) { + return ""+c; + } + + // check for alphanumeric characters + String hex = super.getHexForNonAlphanumeric(c); + if ( hex == null ) { + return ""+c; + } + + // Do not use these shortcuts as they can be used to break out of a context + // if ( ch == 0x00 ) return "\\0"; + // if ( ch == 0x08 ) return "\\b"; + // if ( ch == 0x09 ) return "\\t"; + // if ( ch == 0x0a ) return "\\n"; + // if ( ch == 0x0b ) return "\\v"; + // if ( ch == 0x0c ) return "\\f"; + // if ( ch == 0x0d ) return "\\r"; + // if ( ch == 0x22 ) return "\\\""; + // if ( ch == 0x27 ) return "\\'"; + // if ( ch == 0x5c ) return "\\\\"; - // encode up to 256 with \\xHH + // encode up to 256 with \\xHH String temp = Integer.toHexString(c); - if ( c < 256 ) { - String pad = "00".substring(temp.length() ); - return "\\x" + pad + temp.toUpperCase(); - } + if ( c < 256 ) { + String pad = "00".substring(temp.length() ); + return "\\x" + pad + temp.toUpperCase(); + } - // otherwise encode with \\uHHHH + // otherwise encode with \\uHHHH String pad = "0000".substring(temp.length() ); return "\\u" + pad + temp.toUpperCase(); - } + } - - /** - * {@inheritDoc} - * - * Returns the decoded version of the character starting at index, or - * null if no decoding is possible. - * See http://www.planetpdf.com/codecuts/pdfs/tutorial/jsspec.pdf - * Formats all are legal both upper/lower case: - * \\a - special characters - * \\xHH - * \\uHHHH - * \\OOO (1, 2, or 3 digits) - */ - public Character decodeCharacter( PushbackSequence input ) { - input.mark(); - Character first = input.next(); - if ( first == null ) { - input.reset(); - return null; - } - - // if this is not an encoded character, return null - if (first != '\\' ) { - input.reset(); - return null; - } + + /** + * {@inheritDoc} + * + * Returns the decoded version of the character starting at index, or + * null if no decoding is possible. + * See http://www.planetpdf.com/codecuts/pdfs/tutorial/jsspec.pdf + * Formats all are legal both upper/lower case: + * \\a - special characters + * \\xHH + * \\uHHHH + * \\OOO (1, 2, or 3 digits) + */ + public Character decodeCharacter( PushbackSequence input ) { + input.mark(); + Character first = input.next(); + if ( first == null ) { + input.reset(); + return null; + } + + // if this is not an encoded character, return null + if (first != '\\' ) { + input.reset(); + return null; + } - Character second = input.next(); - if ( second == null ) { - input.reset(); - return null; - } - - // \0 collides with the octal decoder and is non-standard - // if ( second.charValue() == '0' ) { - // return Character.valueOf( (char)0x00 ); - if (second == 'b' ) { - return 0x08; - } else if (second == 't' ) { - return 0x09; - } else if (second == 'n' ) { - return 0x0a; - } else if (second == 'v' ) { - return 0x0b; - } else if (second == 'f' ) { - return 0x0c; - } else if (second == 'r' ) { - return 0x0d; - } else if (second == '\"' ) { - return 0x22; - } else if (second == '\'' ) { - return 0x27; - } else if (second == '\\' ) { - return 0x5c; - - // look for \\xXX format - } else if ( Character.toLowerCase( second.charValue() ) == 'x' ) { - // Search for exactly 2 hex digits following - StringBuilder sb = new StringBuilder(); - for ( int i=0; i<2; i++ ) { - Character c = input.nextHex(); - if ( c != null ) sb.append( c ); - else { - input.reset(); - return null; - } - } - try { - // parse the hex digit and create a character - int i = Integer.parseInt(sb.toString(), 16); + Character second = input.next(); + if ( second == null ) { + input.reset(); + return null; + } + + // \0 collides with the octal decoder and is non-standard + // if ( second.charValue() == '0' ) { + // return Character.valueOf( (char)0x00 ); + if (second == 'b' ) { + return 0x08; + } else if (second == 't' ) { + return 0x09; + } else if (second == 'n' ) { + return 0x0a; + } else if (second == 'v' ) { + return 0x0b; + } else if (second == 'f' ) { + return 0x0c; + } else if (second == 'r' ) { + return 0x0d; + } else if (second == '\"' ) { + return 0x22; + } else if (second == '\'' ) { + return 0x27; + } else if (second == '\\' ) { + return 0x5c; + + // look for \\xXX format + } else if ( Character.toLowerCase( second.charValue() ) == 'x' ) { + // Search for exactly 2 hex digits following + StringBuilder sb = new StringBuilder(); + for ( int i=0; i<2; i++ ) { + Character c = input.nextHex(); + if ( c != null ) sb.append( c ); + else { + input.reset(); + return null; + } + } + try { + // parse the hex digit and create a character + int i = Integer.parseInt(sb.toString(), 16); if (Character.isValidCodePoint(i)) { return (char) i; } - } catch( NumberFormatException e ) { - // throw an exception for malformed entity? - input.reset(); - return null; - } - - // look for \\uXXXX format - } else if ( Character.toLowerCase( second.charValue() ) == 'u') { - // Search for exactly 4 hex digits following - StringBuilder sb = new StringBuilder(); - for ( int i=0; i<4; i++ ) { - Character c = input.nextHex(); - if ( c != null ) sb.append( c ); - else { - input.reset(); - return null; - } - } - try { - // parse the hex string and create a character - int i = Integer.parseInt(sb.toString(), 16); + } catch( NumberFormatException e ) { + // throw an exception for malformed entity? + input.reset(); + return null; + } + + // look for \\uXXXX format + } else if ( Character.toLowerCase( second.charValue() ) == 'u') { + // Search for exactly 4 hex digits following + StringBuilder sb = new StringBuilder(); + for ( int i=0; i<4; i++ ) { + Character c = input.nextHex(); + if ( c != null ) sb.append( c ); + else { + input.reset(); + return null; + } + } + try { + // parse the hex string and create a character + int i = Integer.parseInt(sb.toString(), 16); if (Character.isValidCodePoint(i)) { return (char) i; } - } catch( NumberFormatException e ) { - // throw an exception for malformed entity? - input.reset(); - return null; - } - - // look for one, two, or three octal digits - } else if ( PushbackString.isOctalDigit(second) ) { - StringBuilder sb = new StringBuilder(); + } catch( NumberFormatException e ) { + // throw an exception for malformed entity? + input.reset(); + return null; + } + + // look for one, two, or three octal digits + } else if ( PushbackString.isOctalDigit(second) ) { + StringBuilder sb = new StringBuilder(); // get digit 1 sb.append(second); // get digit 2 if present Character c2 = input.next(); if ( !PushbackString.isOctalDigit(c2) ) { - input.pushback( c2 ); + input.pushback( c2 ); } else { - sb.append( c2 ); - // get digit 3 if present - Character c3 = input.next(); - if ( !PushbackString.isOctalDigit(c3) ) { - input.pushback( c3 ); - } else { - sb.append( c3 ); - } + sb.append( c2 ); + // get digit 3 if present + Character c3 = input.next(); + if ( !PushbackString.isOctalDigit(c3) ) { + input.pushback( c3 ); + } else { + sb.append( c3 ); + } } - try { - // parse the octal string and create a character - int i = Integer.parseInt(sb.toString(), 8); + try { + // parse the octal string and create a character + int i = Integer.parseInt(sb.toString(), 8); if (Character.isValidCodePoint(i)) { return (char) i; } - } catch( NumberFormatException e ) { - // throw an exception for malformed entity? - input.reset(); - return null; - } - } - - // ignore the backslash and return the character - input.reset(); - return null; - } + } catch( NumberFormatException e ) { + // throw an exception for malformed entity? + input.reset(); + return null; + } + } + + // ignore the backslash and return the character + input.reset(); + return null; + } } \ No newline at end of file diff --git a/src/main/java/org/owasp/esapi/codecs/LegacyHTMLEntityCodec.java b/src/main/java/org/owasp/esapi/codecs/LegacyHTMLEntityCodec.java index 31d6960f4..1789efd2b 100644 --- a/src/main/java/org/owasp/esapi/codecs/LegacyHTMLEntityCodec.java +++ b/src/main/java/org/owasp/esapi/codecs/LegacyHTMLEntityCodec.java @@ -35,523 +35,523 @@ */ @Deprecated public class LegacyHTMLEntityCodec extends AbstractCharacterCodec { - - private static final char REPLACEMENT_CHAR = '\ufffd'; - private static final String REPLACEMENT_HEX = "fffd"; - private static final String REPLACEMENT_STR = "" + REPLACEMENT_CHAR; - private static final Map characterToEntityMap = mkCharacterToEntityMap(); - private static final Trie entityToCharacterTrie = mkEntityToCharacterTrie(); + + private static final char REPLACEMENT_CHAR = '\ufffd'; + private static final String REPLACEMENT_HEX = "fffd"; + private static final String REPLACEMENT_STR = "" + REPLACEMENT_CHAR; + private static final Map characterToEntityMap = mkCharacterToEntityMap(); + private static final Trie entityToCharacterTrie = mkEntityToCharacterTrie(); - /** - * {@inheritDoc} - * + /** + * {@inheritDoc} + * * Encodes a Character for safe use in an HTML entity field. * @param immune */ - public String encodeCharacter( char[] immune, Character c ) { + public String encodeCharacter( char[] immune, Character c ) { - // check for immune characters - if ( containsCharacter(c, immune ) ) { - return ""+c; - } - - // check for alphanumeric characters - String hex = super.getHexForNonAlphanumeric(c); - if ( hex == null ) { - return ""+c; - } - - // check for illegal characters - if ( ( c <= 0x1f && c != '\t' && c != '\n' && c != '\r' ) || ( c >= 0x7f && c <= 0x9f ) ) - { - hex = REPLACEMENT_HEX; // Let's entity encode this instead of returning it - c = REPLACEMENT_CHAR; - } - - // check if there's a defined entity - String entityName = characterToEntityMap.get(c); - if (entityName != null) { - return "&" + entityName + ";"; - } - - // return the hex entity as suggested in the spec - return "&#x" + hex + ";"; - } - - /** - * Returns the decoded version of the character starting at index, or - * null if no decoding is possible. - * - * Formats all are legal both with and without semi-colon, upper/lower case: - * &#dddd; - * &#xhhhh; - * &name; - */ - public Character decodeCharacter( PushbackString input ) { - input.mark(); - Character first = input.next(); - if ( first == null ) { - input.reset(); - return null; - } - - // if this is not an encoded character, return null - if (first != '&' ) { - input.reset(); - return null; - } - - // test for numeric encodings - Character second = input.next(); - if ( second == null ) { - input.reset(); - return null; - } - - if (second == '#' ) { - // handle numbers - Character c = getNumericEntity( input ); - if ( c != null ) return c; - } else if ( Character.isLetter( second.charValue() ) ) { - // handle entities - input.pushback( second ); - Character c = getNamedEntity( input ); - if ( c != null ) return c; - } - input.reset(); - return null; - } - - /** - * getNumericEntry checks input to see if it is a numeric entity - * - * @param input - * The input to test for being a numeric entity - * - * @return - * null if input is null, the character of input after decoding - */ - private Character getNumericEntity( PushbackString input ) { - Character first = input.peek(); - if ( first == null ) return null; + // check for immune characters + if ( containsCharacter(c, immune ) ) { + return ""+c; + } + + // check for alphanumeric characters + String hex = super.getHexForNonAlphanumeric(c); + if ( hex == null ) { + return ""+c; + } + + // check for illegal characters + if ( ( c <= 0x1f && c != '\t' && c != '\n' && c != '\r' ) || ( c >= 0x7f && c <= 0x9f ) ) + { + hex = REPLACEMENT_HEX; // Let's entity encode this instead of returning it + c = REPLACEMENT_CHAR; + } + + // check if there's a defined entity + String entityName = characterToEntityMap.get(c); + if (entityName != null) { + return "&" + entityName + ";"; + } + + // return the hex entity as suggested in the spec + return "&#x" + hex + ";"; + } + + /** + * Returns the decoded version of the character starting at index, or + * null if no decoding is possible. + * + * Formats all are legal both with and without semi-colon, upper/lower case: + * &#dddd; + * &#xhhhh; + * &name; + */ + public Character decodeCharacter( PushbackString input ) { + input.mark(); + Character first = input.next(); + if ( first == null ) { + input.reset(); + return null; + } + + // if this is not an encoded character, return null + if (first != '&' ) { + input.reset(); + return null; + } + + // test for numeric encodings + Character second = input.next(); + if ( second == null ) { + input.reset(); + return null; + } + + if (second == '#' ) { + // handle numbers + Character c = getNumericEntity( input ); + if ( c != null ) return c; + } else if ( Character.isLetter( second.charValue() ) ) { + // handle entities + input.pushback( second ); + Character c = getNamedEntity( input ); + if ( c != null ) return c; + } + input.reset(); + return null; + } + + /** + * getNumericEntry checks input to see if it is a numeric entity + * + * @param input + * The input to test for being a numeric entity + * + * @return + * null if input is null, the character of input after decoding + */ + private Character getNumericEntity( PushbackString input ) { + Character first = input.peek(); + if ( first == null ) return null; - if (first == 'x' || first == 'X' ) { - input.next(); - return parseHex( input ); - } - return parseNumber( input ); - } + if (first == 'x' || first == 'X' ) { + input.next(); + return parseHex( input ); + } + return parseNumber( input ); + } - /** - * Parse a decimal number, such as those from JavaScript's String.fromCharCode(value) - * - * @param input - * decimal encoded string, such as 65 - * @return - * character representation of this decimal value, e.g. A - * @throws NumberFormatException - */ - private Character parseNumber( PushbackString input ) { - StringBuilder sb = new StringBuilder(); - while( input.hasNext() ) { - Character c = input.peek(); - - // if character is a digit then add it on and keep going - if ( Character.isDigit( c.charValue() ) ) { - sb.append( c ); - input.next(); - - // if character is a semi-colon, eat it and quit - } else if (c == ';' ) { - input.next(); - break; - - // otherwise just quit - } else { - break; - } - } - try { - int i = Integer.parseInt(sb.toString()); + /** + * Parse a decimal number, such as those from JavaScript's String.fromCharCode(value) + * + * @param input + * decimal encoded string, such as 65 + * @return + * character representation of this decimal value, e.g. A + * @throws NumberFormatException + */ + private Character parseNumber( PushbackString input ) { + StringBuilder sb = new StringBuilder(); + while( input.hasNext() ) { + Character c = input.peek(); + + // if character is a digit then add it on and keep going + if ( Character.isDigit( c.charValue() ) ) { + sb.append( c ); + input.next(); + + // if character is a semi-colon, eat it and quit + } else if (c == ';' ) { + input.next(); + break; + + // otherwise just quit + } else { + break; + } + } + try { + int i = Integer.parseInt(sb.toString()); if (Character.isValidCodePoint(i)) { return (char) i; } - } catch( NumberFormatException e ) { - // throw an exception for malformed entity? - } - return null; - } - - /** - * Parse a hex encoded entity - * - * @param input - * Hex encoded input (such as 437ae;) - * @return - * A single character from the string - * @throws NumberFormatException - */ - private Character parseHex( PushbackString input ) { - StringBuilder sb = new StringBuilder(); - while( input.hasNext() ) { - Character c = input.peek(); - - // if character is a hex digit then add it on and keep going - if ( "0123456789ABCDEFabcdef".indexOf(c) != -1 ) { - sb.append( c ); - input.next(); - - // if character is a semi-colon, eat it and quit - } else if (c == ';' ) { - input.next(); - break; - - // otherwise just quit - } else { - break; - } - } - try { - int i = Integer.parseInt(sb.toString(), 16); + } catch( NumberFormatException e ) { + // throw an exception for malformed entity? + } + return null; + } + + /** + * Parse a hex encoded entity + * + * @param input + * Hex encoded input (such as 437ae;) + * @return + * A single character from the string + * @throws NumberFormatException + */ + private Character parseHex( PushbackString input ) { + StringBuilder sb = new StringBuilder(); + while( input.hasNext() ) { + Character c = input.peek(); + + // if character is a hex digit then add it on and keep going + if ( "0123456789ABCDEFabcdef".indexOf(c) != -1 ) { + sb.append( c ); + input.next(); + + // if character is a semi-colon, eat it and quit + } else if (c == ';' ) { + input.next(); + break; + + // otherwise just quit + } else { + break; + } + } + try { + int i = Integer.parseInt(sb.toString(), 16); if (Character.isValidCodePoint(i)) { return (char) i; } - } catch( NumberFormatException e ) { - // throw an exception for malformed entity? - } - return null; - } - - /** - * - * Returns the decoded version of the character starting at index, or - * null if no decoding is possible. - * - * Formats all are legal both with and without semi-colon, upper/lower case: - * &aa; - * &aaa; - * &aaaa; - * &aaaaa; - * &aaaaaa; - * &aaaaaaa; - * - * @param input - * A string containing a named entity like " - * @return - * Returns the decoded version of the character starting at index, or null if no decoding is possible. - */ - private Character getNamedEntity( PushbackString input ) { - StringBuilder possible = new StringBuilder(); - Map.Entry entry; - int len; - - // kludge around PushbackString.... - len = Math.min(input.remainder().length(), entityToCharacterTrie.getMaxKeyLength()); - for(int i=0;i entry; + int len; + + // kludge around PushbackString.... + len = Math.min(input.remainder().length(), entityToCharacterTrie.getMaxKeyLength()); + for(int i=0;i exactEntry = entityToCharacterTrie.getLongestMatch(possibleStringLowerCase); - if(exactEntry != null) entry = exactEntry; - } - if(entry == null) return null; // no match, caller will reset input - } + // look up the longest match + entry = entityToCharacterTrie.getLongestMatch(possible); + if(entry == null) { + // We are lowercasing & comparing the result because of this all the upper case named entities are getting converted lowercase named entities. + // check is there any exact match https://github.com/ESAPI/esapi-java-legacy/issues/302 + String possibleString = possible.toString(); + String possibleStringLowerCase = possibleString.toLowerCase(); + if(!possibleString.equals(possibleStringLowerCase)) { + Map.Entry exactEntry = entityToCharacterTrie.getLongestMatch(possibleStringLowerCase); + if(exactEntry != null) entry = exactEntry; + } + if(entry == null) return null; // no match, caller will reset input + } - // fixup input - input.reset(); - input.next(); // read & - len = entry.getKey().length(); // what matched's length - for(int i=0;i mkCharacterToEntityMap() - { - Map map = new HashMap(252); + /** + * Build a unmodifiable Map from entity Character to Name. + * @return Unmodifiable map. + */ + private static synchronized Map mkCharacterToEntityMap() + { + Map map = new HashMap(252); - map.put((char)34, "quot"); /* quotation mark */ - map.put((char)38, "amp"); /* ampersand */ - map.put((char)60, "lt"); /* less-than sign */ - map.put((char)62, "gt"); /* greater-than sign */ - map.put((char)160, "nbsp"); /* no-break space */ - map.put((char)161, "iexcl"); /* inverted exclamation mark */ - map.put((char)162, "cent"); /* cent sign */ - map.put((char)163, "pound"); /* pound sign */ - map.put((char)164, "curren"); /* currency sign */ - map.put((char)165, "yen"); /* yen sign */ - map.put((char)166, "brvbar"); /* broken bar */ - map.put((char)167, "sect"); /* section sign */ - map.put((char)168, "uml"); /* diaeresis */ - map.put((char)169, "copy"); /* copyright sign */ - map.put((char)170, "ordf"); /* feminine ordinal indicator */ - map.put((char)171, "laquo"); /* left-pointing double angle quotation mark */ - map.put((char)172, "not"); /* not sign */ - map.put((char)173, "shy"); /* soft hyphen */ - map.put((char)174, "reg"); /* registered sign */ - map.put((char)175, "macr"); /* macron */ - map.put((char)176, "deg"); /* degree sign */ - map.put((char)177, "plusmn"); /* plus-minus sign */ - map.put((char)178, "sup2"); /* superscript two */ - map.put((char)179, "sup3"); /* superscript three */ - map.put((char)180, "acute"); /* acute accent */ - map.put((char)181, "micro"); /* micro sign */ - map.put((char)182, "para"); /* pilcrow sign */ - map.put((char)183, "middot"); /* middle dot */ - map.put((char)184, "cedil"); /* cedilla */ - map.put((char)185, "sup1"); /* superscript one */ - map.put((char)186, "ordm"); /* masculine ordinal indicator */ - map.put((char)187, "raquo"); /* right-pointing double angle quotation mark */ - map.put((char)188, "frac14"); /* vulgar fraction one quarter */ - map.put((char)189, "frac12"); /* vulgar fraction one half */ - map.put((char)190, "frac34"); /* vulgar fraction three quarters */ - map.put((char)191, "iquest"); /* inverted question mark */ - map.put((char)192, "Agrave"); /* Latin capital letter a with grave */ - map.put((char)193, "Aacute"); /* Latin capital letter a with acute */ - map.put((char)194, "Acirc"); /* Latin capital letter a with circumflex */ - map.put((char)195, "Atilde"); /* Latin capital letter a with tilde */ - map.put((char)196, "Auml"); /* Latin capital letter a with diaeresis */ - map.put((char)197, "Aring"); /* Latin capital letter a with ring above */ - map.put((char)198, "AElig"); /* Latin capital letter ae */ - map.put((char)199, "Ccedil"); /* Latin capital letter c with cedilla */ - map.put((char)200, "Egrave"); /* Latin capital letter e with grave */ - map.put((char)201, "Eacute"); /* Latin capital letter e with acute */ - map.put((char)202, "Ecirc"); /* Latin capital letter e with circumflex */ - map.put((char)203, "Euml"); /* Latin capital letter e with diaeresis */ - map.put((char)204, "Igrave"); /* Latin capital letter i with grave */ - map.put((char)205, "Iacute"); /* Latin capital letter i with acute */ - map.put((char)206, "Icirc"); /* Latin capital letter i with circumflex */ - map.put((char)207, "Iuml"); /* Latin capital letter i with diaeresis */ - map.put((char)208, "ETH"); /* Latin capital letter eth */ - map.put((char)209, "Ntilde"); /* Latin capital letter n with tilde */ - map.put((char)210, "Ograve"); /* Latin capital letter o with grave */ - map.put((char)211, "Oacute"); /* Latin capital letter o with acute */ - map.put((char)212, "Ocirc"); /* Latin capital letter o with circumflex */ - map.put((char)213, "Otilde"); /* Latin capital letter o with tilde */ - map.put((char)214, "Ouml"); /* Latin capital letter o with diaeresis */ - map.put((char)215, "times"); /* multiplication sign */ - map.put((char)216, "Oslash"); /* Latin capital letter o with stroke */ - map.put((char)217, "Ugrave"); /* Latin capital letter u with grave */ - map.put((char)218, "Uacute"); /* Latin capital letter u with acute */ - map.put((char)219, "Ucirc"); /* Latin capital letter u with circumflex */ - map.put((char)220, "Uuml"); /* Latin capital letter u with diaeresis */ - map.put((char)221, "Yacute"); /* Latin capital letter y with acute */ - map.put((char)222, "THORN"); /* Latin capital letter thorn */ - map.put((char)223, "szlig"); /* Latin small letter sharp sXCOMMAX German Eszett */ - map.put((char)224, "agrave"); /* Latin small letter a with grave */ - map.put((char)225, "aacute"); /* Latin small letter a with acute */ - map.put((char)226, "acirc"); /* Latin small letter a with circumflex */ - map.put((char)227, "atilde"); /* Latin small letter a with tilde */ - map.put((char)228, "auml"); /* Latin small letter a with diaeresis */ - map.put((char)229, "aring"); /* Latin small letter a with ring above */ - map.put((char)230, "aelig"); /* Latin lowercase ligature ae */ - map.put((char)231, "ccedil"); /* Latin small letter c with cedilla */ - map.put((char)232, "egrave"); /* Latin small letter e with grave */ - map.put((char)233, "eacute"); /* Latin small letter e with acute */ - map.put((char)234, "ecirc"); /* Latin small letter e with circumflex */ - map.put((char)235, "euml"); /* Latin small letter e with diaeresis */ - map.put((char)236, "igrave"); /* Latin small letter i with grave */ - map.put((char)237, "iacute"); /* Latin small letter i with acute */ - map.put((char)238, "icirc"); /* Latin small letter i with circumflex */ - map.put((char)239, "iuml"); /* Latin small letter i with diaeresis */ - map.put((char)240, "eth"); /* Latin small letter eth */ - map.put((char)241, "ntilde"); /* Latin small letter n with tilde */ - map.put((char)242, "ograve"); /* Latin small letter o with grave */ - map.put((char)243, "oacute"); /* Latin small letter o with acute */ - map.put((char)244, "ocirc"); /* Latin small letter o with circumflex */ - map.put((char)245, "otilde"); /* Latin small letter o with tilde */ - map.put((char)246, "ouml"); /* Latin small letter o with diaeresis */ - map.put((char)247, "divide"); /* division sign */ - map.put((char)248, "oslash"); /* Latin small letter o with stroke */ - map.put((char)249, "ugrave"); /* Latin small letter u with grave */ - map.put((char)250, "uacute"); /* Latin small letter u with acute */ - map.put((char)251, "ucirc"); /* Latin small letter u with circumflex */ - map.put((char)252, "uuml"); /* Latin small letter u with diaeresis */ - map.put((char)253, "yacute"); /* Latin small letter y with acute */ - map.put((char)254, "thorn"); /* Latin small letter thorn */ - map.put((char)255, "yuml"); /* Latin small letter y with diaeresis */ - map.put((char)338, "OElig"); /* Latin capital ligature oe */ - map.put((char)339, "oelig"); /* Latin small ligature oe */ - map.put((char)352, "Scaron"); /* Latin capital letter s with caron */ - map.put((char)353, "scaron"); /* Latin small letter s with caron */ - map.put((char)376, "Yuml"); /* Latin capital letter y with diaeresis */ - map.put((char)402, "fnof"); /* Latin small letter f with hook */ - map.put((char)710, "circ"); /* modifier letter circumflex accent */ - map.put((char)732, "tilde"); /* small tilde */ - map.put((char)913, "Alpha"); /* Greek capital letter alpha */ - map.put((char)914, "Beta"); /* Greek capital letter beta */ - map.put((char)915, "Gamma"); /* Greek capital letter gamma */ - map.put((char)916, "Delta"); /* Greek capital letter delta */ - map.put((char)917, "Epsilon"); /* Greek capital letter epsilon */ - map.put((char)918, "Zeta"); /* Greek capital letter zeta */ - map.put((char)919, "Eta"); /* Greek capital letter eta */ - map.put((char)920, "Theta"); /* Greek capital letter theta */ - map.put((char)921, "Iota"); /* Greek capital letter iota */ - map.put((char)922, "Kappa"); /* Greek capital letter kappa */ - map.put((char)923, "Lambda"); /* Greek capital letter lambda */ - map.put((char)924, "Mu"); /* Greek capital letter mu */ - map.put((char)925, "Nu"); /* Greek capital letter nu */ - map.put((char)926, "Xi"); /* Greek capital letter xi */ - map.put((char)927, "Omicron"); /* Greek capital letter omicron */ - map.put((char)928, "Pi"); /* Greek capital letter pi */ - map.put((char)929, "Rho"); /* Greek capital letter rho */ - map.put((char)931, "Sigma"); /* Greek capital letter sigma */ - map.put((char)932, "Tau"); /* Greek capital letter tau */ - map.put((char)933, "Upsilon"); /* Greek capital letter upsilon */ - map.put((char)934, "Phi"); /* Greek capital letter phi */ - map.put((char)935, "Chi"); /* Greek capital letter chi */ - map.put((char)936, "Psi"); /* Greek capital letter psi */ - map.put((char)937, "Omega"); /* Greek capital letter omega */ - map.put((char)945, "alpha"); /* Greek small letter alpha */ - map.put((char)946, "beta"); /* Greek small letter beta */ - map.put((char)947, "gamma"); /* Greek small letter gamma */ - map.put((char)948, "delta"); /* Greek small letter delta */ - map.put((char)949, "epsilon"); /* Greek small letter epsilon */ - map.put((char)950, "zeta"); /* Greek small letter zeta */ - map.put((char)951, "eta"); /* Greek small letter eta */ - map.put((char)952, "theta"); /* Greek small letter theta */ - map.put((char)953, "iota"); /* Greek small letter iota */ - map.put((char)954, "kappa"); /* Greek small letter kappa */ - map.put((char)955, "lambda"); /* Greek small letter lambda */ - map.put((char)956, "mu"); /* Greek small letter mu */ - map.put((char)957, "nu"); /* Greek small letter nu */ - map.put((char)958, "xi"); /* Greek small letter xi */ - map.put((char)959, "omicron"); /* Greek small letter omicron */ - map.put((char)960, "pi"); /* Greek small letter pi */ - map.put((char)961, "rho"); /* Greek small letter rho */ - map.put((char)962, "sigmaf"); /* Greek small letter final sigma */ - map.put((char)963, "sigma"); /* Greek small letter sigma */ - map.put((char)964, "tau"); /* Greek small letter tau */ - map.put((char)965, "upsilon"); /* Greek small letter upsilon */ - map.put((char)966, "phi"); /* Greek small letter phi */ - map.put((char)967, "chi"); /* Greek small letter chi */ - map.put((char)968, "psi"); /* Greek small letter psi */ - map.put((char)969, "omega"); /* Greek small letter omega */ - map.put((char)977, "thetasym"); /* Greek theta symbol */ - map.put((char)978, "upsih"); /* Greek upsilon with hook symbol */ - map.put((char)982, "piv"); /* Greek pi symbol */ - map.put((char)8194, "ensp"); /* en space */ - map.put((char)8195, "emsp"); /* em space */ - map.put((char)8201, "thinsp"); /* thin space */ - map.put((char)8204, "zwnj"); /* zero width non-joiner */ - map.put((char)8205, "zwj"); /* zero width joiner */ - map.put((char)8206, "lrm"); /* left-to-right mark */ - map.put((char)8207, "rlm"); /* right-to-left mark */ - map.put((char)8211, "ndash"); /* en dash */ - map.put((char)8212, "mdash"); /* em dash */ - map.put((char)8216, "lsquo"); /* left single quotation mark */ - map.put((char)8217, "rsquo"); /* right single quotation mark */ - map.put((char)8218, "sbquo"); /* single low-9 quotation mark */ - map.put((char)8220, "ldquo"); /* left double quotation mark */ - map.put((char)8221, "rdquo"); /* right double quotation mark */ - map.put((char)8222, "bdquo"); /* double low-9 quotation mark */ - map.put((char)8224, "dagger"); /* dagger */ - map.put((char)8225, "Dagger"); /* double dagger */ - map.put((char)8226, "bull"); /* bullet */ - map.put((char)8230, "hellip"); /* horizontal ellipsis */ - map.put((char)8240, "permil"); /* per mille sign */ - map.put((char)8242, "prime"); /* prime */ - map.put((char)8243, "Prime"); /* double prime */ - map.put((char)8249, "lsaquo"); /* single left-pointing angle quotation mark */ - map.put((char)8250, "rsaquo"); /* single right-pointing angle quotation mark */ - map.put((char)8254, "oline"); /* overline */ - map.put((char)8260, "frasl"); /* fraction slash */ - map.put((char)8364, "euro"); /* euro sign */ - map.put((char)8465, "image"); /* black-letter capital i */ - map.put((char)8472, "weierp"); /* script capital pXCOMMAX Weierstrass p */ - map.put((char)8476, "real"); /* black-letter capital r */ - map.put((char)8482, "trade"); /* trademark sign */ - map.put((char)8501, "alefsym"); /* alef symbol */ - map.put((char)8592, "larr"); /* leftwards arrow */ - map.put((char)8593, "uarr"); /* upwards arrow */ - map.put((char)8594, "rarr"); /* rightwards arrow */ - map.put((char)8595, "darr"); /* downwards arrow */ - map.put((char)8596, "harr"); /* left right arrow */ - map.put((char)8629, "crarr"); /* downwards arrow with corner leftwards */ - map.put((char)8656, "lArr"); /* leftwards double arrow */ - map.put((char)8657, "uArr"); /* upwards double arrow */ - map.put((char)8658, "rArr"); /* rightwards double arrow */ - map.put((char)8659, "dArr"); /* downwards double arrow */ - map.put((char)8660, "hArr"); /* left right double arrow */ - map.put((char)8704, "forall"); /* for all */ - map.put((char)8706, "part"); /* partial differential */ - map.put((char)8707, "exist"); /* there exists */ - map.put((char)8709, "empty"); /* empty set */ - map.put((char)8711, "nabla"); /* nabla */ - map.put((char)8712, "isin"); /* element of */ - map.put((char)8713, "notin"); /* not an element of */ - map.put((char)8715, "ni"); /* contains as member */ - map.put((char)8719, "prod"); /* n-ary product */ - map.put((char)8721, "sum"); /* n-ary summation */ - map.put((char)8722, "minus"); /* minus sign */ - map.put((char)8727, "lowast"); /* asterisk operator */ - map.put((char)8730, "radic"); /* square root */ - map.put((char)8733, "prop"); /* proportional to */ - map.put((char)8734, "infin"); /* infinity */ - map.put((char)8736, "ang"); /* angle */ - map.put((char)8743, "and"); /* logical and */ - map.put((char)8744, "or"); /* logical or */ - map.put((char)8745, "cap"); /* intersection */ - map.put((char)8746, "cup"); /* union */ - map.put((char)8747, "int"); /* integral */ - map.put((char)8756, "there4"); /* therefore */ - map.put((char)8764, "sim"); /* tilde operator */ - map.put((char)8773, "cong"); /* congruent to */ - map.put((char)8776, "asymp"); /* almost equal to */ - map.put((char)8800, "ne"); /* not equal to */ - map.put((char)8801, "equiv"); /* identical toXCOMMAX equivalent to */ - map.put((char)8804, "le"); /* less-than or equal to */ - map.put((char)8805, "ge"); /* greater-than or equal to */ - map.put((char)8834, "sub"); /* subset of */ - map.put((char)8835, "sup"); /* superset of */ - map.put((char)8836, "nsub"); /* not a subset of */ - map.put((char)8838, "sube"); /* subset of or equal to */ - map.put((char)8839, "supe"); /* superset of or equal to */ - map.put((char)8853, "oplus"); /* circled plus */ - map.put((char)8855, "otimes"); /* circled times */ - map.put((char)8869, "perp"); /* up tack */ - map.put((char)8901, "sdot"); /* dot operator */ - map.put((char)8968, "lceil"); /* left ceiling */ - map.put((char)8969, "rceil"); /* right ceiling */ - map.put((char)8970, "lfloor"); /* left floor */ - map.put((char)8971, "rfloor"); /* right floor */ - map.put((char)9001, "lang"); /* left-pointing angle bracket */ - map.put((char)9002, "rang"); /* right-pointing angle bracket */ - map.put((char)9674, "loz"); /* lozenge */ - map.put((char)9824, "spades"); /* black spade suit */ - map.put((char)9827, "clubs"); /* black club suit */ - map.put((char)9829, "hearts"); /* black heart suit */ - map.put((char)9830, "diams"); /* black diamond suit */ + map.put((char)34, "quot"); /* quotation mark */ + map.put((char)38, "amp"); /* ampersand */ + map.put((char)60, "lt"); /* less-than sign */ + map.put((char)62, "gt"); /* greater-than sign */ + map.put((char)160, "nbsp"); /* no-break space */ + map.put((char)161, "iexcl"); /* inverted exclamation mark */ + map.put((char)162, "cent"); /* cent sign */ + map.put((char)163, "pound"); /* pound sign */ + map.put((char)164, "curren"); /* currency sign */ + map.put((char)165, "yen"); /* yen sign */ + map.put((char)166, "brvbar"); /* broken bar */ + map.put((char)167, "sect"); /* section sign */ + map.put((char)168, "uml"); /* diaeresis */ + map.put((char)169, "copy"); /* copyright sign */ + map.put((char)170, "ordf"); /* feminine ordinal indicator */ + map.put((char)171, "laquo"); /* left-pointing double angle quotation mark */ + map.put((char)172, "not"); /* not sign */ + map.put((char)173, "shy"); /* soft hyphen */ + map.put((char)174, "reg"); /* registered sign */ + map.put((char)175, "macr"); /* macron */ + map.put((char)176, "deg"); /* degree sign */ + map.put((char)177, "plusmn"); /* plus-minus sign */ + map.put((char)178, "sup2"); /* superscript two */ + map.put((char)179, "sup3"); /* superscript three */ + map.put((char)180, "acute"); /* acute accent */ + map.put((char)181, "micro"); /* micro sign */ + map.put((char)182, "para"); /* pilcrow sign */ + map.put((char)183, "middot"); /* middle dot */ + map.put((char)184, "cedil"); /* cedilla */ + map.put((char)185, "sup1"); /* superscript one */ + map.put((char)186, "ordm"); /* masculine ordinal indicator */ + map.put((char)187, "raquo"); /* right-pointing double angle quotation mark */ + map.put((char)188, "frac14"); /* vulgar fraction one quarter */ + map.put((char)189, "frac12"); /* vulgar fraction one half */ + map.put((char)190, "frac34"); /* vulgar fraction three quarters */ + map.put((char)191, "iquest"); /* inverted question mark */ + map.put((char)192, "Agrave"); /* Latin capital letter a with grave */ + map.put((char)193, "Aacute"); /* Latin capital letter a with acute */ + map.put((char)194, "Acirc"); /* Latin capital letter a with circumflex */ + map.put((char)195, "Atilde"); /* Latin capital letter a with tilde */ + map.put((char)196, "Auml"); /* Latin capital letter a with diaeresis */ + map.put((char)197, "Aring"); /* Latin capital letter a with ring above */ + map.put((char)198, "AElig"); /* Latin capital letter ae */ + map.put((char)199, "Ccedil"); /* Latin capital letter c with cedilla */ + map.put((char)200, "Egrave"); /* Latin capital letter e with grave */ + map.put((char)201, "Eacute"); /* Latin capital letter e with acute */ + map.put((char)202, "Ecirc"); /* Latin capital letter e with circumflex */ + map.put((char)203, "Euml"); /* Latin capital letter e with diaeresis */ + map.put((char)204, "Igrave"); /* Latin capital letter i with grave */ + map.put((char)205, "Iacute"); /* Latin capital letter i with acute */ + map.put((char)206, "Icirc"); /* Latin capital letter i with circumflex */ + map.put((char)207, "Iuml"); /* Latin capital letter i with diaeresis */ + map.put((char)208, "ETH"); /* Latin capital letter eth */ + map.put((char)209, "Ntilde"); /* Latin capital letter n with tilde */ + map.put((char)210, "Ograve"); /* Latin capital letter o with grave */ + map.put((char)211, "Oacute"); /* Latin capital letter o with acute */ + map.put((char)212, "Ocirc"); /* Latin capital letter o with circumflex */ + map.put((char)213, "Otilde"); /* Latin capital letter o with tilde */ + map.put((char)214, "Ouml"); /* Latin capital letter o with diaeresis */ + map.put((char)215, "times"); /* multiplication sign */ + map.put((char)216, "Oslash"); /* Latin capital letter o with stroke */ + map.put((char)217, "Ugrave"); /* Latin capital letter u with grave */ + map.put((char)218, "Uacute"); /* Latin capital letter u with acute */ + map.put((char)219, "Ucirc"); /* Latin capital letter u with circumflex */ + map.put((char)220, "Uuml"); /* Latin capital letter u with diaeresis */ + map.put((char)221, "Yacute"); /* Latin capital letter y with acute */ + map.put((char)222, "THORN"); /* Latin capital letter thorn */ + map.put((char)223, "szlig"); /* Latin small letter sharp sXCOMMAX German Eszett */ + map.put((char)224, "agrave"); /* Latin small letter a with grave */ + map.put((char)225, "aacute"); /* Latin small letter a with acute */ + map.put((char)226, "acirc"); /* Latin small letter a with circumflex */ + map.put((char)227, "atilde"); /* Latin small letter a with tilde */ + map.put((char)228, "auml"); /* Latin small letter a with diaeresis */ + map.put((char)229, "aring"); /* Latin small letter a with ring above */ + map.put((char)230, "aelig"); /* Latin lowercase ligature ae */ + map.put((char)231, "ccedil"); /* Latin small letter c with cedilla */ + map.put((char)232, "egrave"); /* Latin small letter e with grave */ + map.put((char)233, "eacute"); /* Latin small letter e with acute */ + map.put((char)234, "ecirc"); /* Latin small letter e with circumflex */ + map.put((char)235, "euml"); /* Latin small letter e with diaeresis */ + map.put((char)236, "igrave"); /* Latin small letter i with grave */ + map.put((char)237, "iacute"); /* Latin small letter i with acute */ + map.put((char)238, "icirc"); /* Latin small letter i with circumflex */ + map.put((char)239, "iuml"); /* Latin small letter i with diaeresis */ + map.put((char)240, "eth"); /* Latin small letter eth */ + map.put((char)241, "ntilde"); /* Latin small letter n with tilde */ + map.put((char)242, "ograve"); /* Latin small letter o with grave */ + map.put((char)243, "oacute"); /* Latin small letter o with acute */ + map.put((char)244, "ocirc"); /* Latin small letter o with circumflex */ + map.put((char)245, "otilde"); /* Latin small letter o with tilde */ + map.put((char)246, "ouml"); /* Latin small letter o with diaeresis */ + map.put((char)247, "divide"); /* division sign */ + map.put((char)248, "oslash"); /* Latin small letter o with stroke */ + map.put((char)249, "ugrave"); /* Latin small letter u with grave */ + map.put((char)250, "uacute"); /* Latin small letter u with acute */ + map.put((char)251, "ucirc"); /* Latin small letter u with circumflex */ + map.put((char)252, "uuml"); /* Latin small letter u with diaeresis */ + map.put((char)253, "yacute"); /* Latin small letter y with acute */ + map.put((char)254, "thorn"); /* Latin small letter thorn */ + map.put((char)255, "yuml"); /* Latin small letter y with diaeresis */ + map.put((char)338, "OElig"); /* Latin capital ligature oe */ + map.put((char)339, "oelig"); /* Latin small ligature oe */ + map.put((char)352, "Scaron"); /* Latin capital letter s with caron */ + map.put((char)353, "scaron"); /* Latin small letter s with caron */ + map.put((char)376, "Yuml"); /* Latin capital letter y with diaeresis */ + map.put((char)402, "fnof"); /* Latin small letter f with hook */ + map.put((char)710, "circ"); /* modifier letter circumflex accent */ + map.put((char)732, "tilde"); /* small tilde */ + map.put((char)913, "Alpha"); /* Greek capital letter alpha */ + map.put((char)914, "Beta"); /* Greek capital letter beta */ + map.put((char)915, "Gamma"); /* Greek capital letter gamma */ + map.put((char)916, "Delta"); /* Greek capital letter delta */ + map.put((char)917, "Epsilon"); /* Greek capital letter epsilon */ + map.put((char)918, "Zeta"); /* Greek capital letter zeta */ + map.put((char)919, "Eta"); /* Greek capital letter eta */ + map.put((char)920, "Theta"); /* Greek capital letter theta */ + map.put((char)921, "Iota"); /* Greek capital letter iota */ + map.put((char)922, "Kappa"); /* Greek capital letter kappa */ + map.put((char)923, "Lambda"); /* Greek capital letter lambda */ + map.put((char)924, "Mu"); /* Greek capital letter mu */ + map.put((char)925, "Nu"); /* Greek capital letter nu */ + map.put((char)926, "Xi"); /* Greek capital letter xi */ + map.put((char)927, "Omicron"); /* Greek capital letter omicron */ + map.put((char)928, "Pi"); /* Greek capital letter pi */ + map.put((char)929, "Rho"); /* Greek capital letter rho */ + map.put((char)931, "Sigma"); /* Greek capital letter sigma */ + map.put((char)932, "Tau"); /* Greek capital letter tau */ + map.put((char)933, "Upsilon"); /* Greek capital letter upsilon */ + map.put((char)934, "Phi"); /* Greek capital letter phi */ + map.put((char)935, "Chi"); /* Greek capital letter chi */ + map.put((char)936, "Psi"); /* Greek capital letter psi */ + map.put((char)937, "Omega"); /* Greek capital letter omega */ + map.put((char)945, "alpha"); /* Greek small letter alpha */ + map.put((char)946, "beta"); /* Greek small letter beta */ + map.put((char)947, "gamma"); /* Greek small letter gamma */ + map.put((char)948, "delta"); /* Greek small letter delta */ + map.put((char)949, "epsilon"); /* Greek small letter epsilon */ + map.put((char)950, "zeta"); /* Greek small letter zeta */ + map.put((char)951, "eta"); /* Greek small letter eta */ + map.put((char)952, "theta"); /* Greek small letter theta */ + map.put((char)953, "iota"); /* Greek small letter iota */ + map.put((char)954, "kappa"); /* Greek small letter kappa */ + map.put((char)955, "lambda"); /* Greek small letter lambda */ + map.put((char)956, "mu"); /* Greek small letter mu */ + map.put((char)957, "nu"); /* Greek small letter nu */ + map.put((char)958, "xi"); /* Greek small letter xi */ + map.put((char)959, "omicron"); /* Greek small letter omicron */ + map.put((char)960, "pi"); /* Greek small letter pi */ + map.put((char)961, "rho"); /* Greek small letter rho */ + map.put((char)962, "sigmaf"); /* Greek small letter final sigma */ + map.put((char)963, "sigma"); /* Greek small letter sigma */ + map.put((char)964, "tau"); /* Greek small letter tau */ + map.put((char)965, "upsilon"); /* Greek small letter upsilon */ + map.put((char)966, "phi"); /* Greek small letter phi */ + map.put((char)967, "chi"); /* Greek small letter chi */ + map.put((char)968, "psi"); /* Greek small letter psi */ + map.put((char)969, "omega"); /* Greek small letter omega */ + map.put((char)977, "thetasym"); /* Greek theta symbol */ + map.put((char)978, "upsih"); /* Greek upsilon with hook symbol */ + map.put((char)982, "piv"); /* Greek pi symbol */ + map.put((char)8194, "ensp"); /* en space */ + map.put((char)8195, "emsp"); /* em space */ + map.put((char)8201, "thinsp"); /* thin space */ + map.put((char)8204, "zwnj"); /* zero width non-joiner */ + map.put((char)8205, "zwj"); /* zero width joiner */ + map.put((char)8206, "lrm"); /* left-to-right mark */ + map.put((char)8207, "rlm"); /* right-to-left mark */ + map.put((char)8211, "ndash"); /* en dash */ + map.put((char)8212, "mdash"); /* em dash */ + map.put((char)8216, "lsquo"); /* left single quotation mark */ + map.put((char)8217, "rsquo"); /* right single quotation mark */ + map.put((char)8218, "sbquo"); /* single low-9 quotation mark */ + map.put((char)8220, "ldquo"); /* left double quotation mark */ + map.put((char)8221, "rdquo"); /* right double quotation mark */ + map.put((char)8222, "bdquo"); /* double low-9 quotation mark */ + map.put((char)8224, "dagger"); /* dagger */ + map.put((char)8225, "Dagger"); /* double dagger */ + map.put((char)8226, "bull"); /* bullet */ + map.put((char)8230, "hellip"); /* horizontal ellipsis */ + map.put((char)8240, "permil"); /* per mille sign */ + map.put((char)8242, "prime"); /* prime */ + map.put((char)8243, "Prime"); /* double prime */ + map.put((char)8249, "lsaquo"); /* single left-pointing angle quotation mark */ + map.put((char)8250, "rsaquo"); /* single right-pointing angle quotation mark */ + map.put((char)8254, "oline"); /* overline */ + map.put((char)8260, "frasl"); /* fraction slash */ + map.put((char)8364, "euro"); /* euro sign */ + map.put((char)8465, "image"); /* black-letter capital i */ + map.put((char)8472, "weierp"); /* script capital pXCOMMAX Weierstrass p */ + map.put((char)8476, "real"); /* black-letter capital r */ + map.put((char)8482, "trade"); /* trademark sign */ + map.put((char)8501, "alefsym"); /* alef symbol */ + map.put((char)8592, "larr"); /* leftwards arrow */ + map.put((char)8593, "uarr"); /* upwards arrow */ + map.put((char)8594, "rarr"); /* rightwards arrow */ + map.put((char)8595, "darr"); /* downwards arrow */ + map.put((char)8596, "harr"); /* left right arrow */ + map.put((char)8629, "crarr"); /* downwards arrow with corner leftwards */ + map.put((char)8656, "lArr"); /* leftwards double arrow */ + map.put((char)8657, "uArr"); /* upwards double arrow */ + map.put((char)8658, "rArr"); /* rightwards double arrow */ + map.put((char)8659, "dArr"); /* downwards double arrow */ + map.put((char)8660, "hArr"); /* left right double arrow */ + map.put((char)8704, "forall"); /* for all */ + map.put((char)8706, "part"); /* partial differential */ + map.put((char)8707, "exist"); /* there exists */ + map.put((char)8709, "empty"); /* empty set */ + map.put((char)8711, "nabla"); /* nabla */ + map.put((char)8712, "isin"); /* element of */ + map.put((char)8713, "notin"); /* not an element of */ + map.put((char)8715, "ni"); /* contains as member */ + map.put((char)8719, "prod"); /* n-ary product */ + map.put((char)8721, "sum"); /* n-ary summation */ + map.put((char)8722, "minus"); /* minus sign */ + map.put((char)8727, "lowast"); /* asterisk operator */ + map.put((char)8730, "radic"); /* square root */ + map.put((char)8733, "prop"); /* proportional to */ + map.put((char)8734, "infin"); /* infinity */ + map.put((char)8736, "ang"); /* angle */ + map.put((char)8743, "and"); /* logical and */ + map.put((char)8744, "or"); /* logical or */ + map.put((char)8745, "cap"); /* intersection */ + map.put((char)8746, "cup"); /* union */ + map.put((char)8747, "int"); /* integral */ + map.put((char)8756, "there4"); /* therefore */ + map.put((char)8764, "sim"); /* tilde operator */ + map.put((char)8773, "cong"); /* congruent to */ + map.put((char)8776, "asymp"); /* almost equal to */ + map.put((char)8800, "ne"); /* not equal to */ + map.put((char)8801, "equiv"); /* identical toXCOMMAX equivalent to */ + map.put((char)8804, "le"); /* less-than or equal to */ + map.put((char)8805, "ge"); /* greater-than or equal to */ + map.put((char)8834, "sub"); /* subset of */ + map.put((char)8835, "sup"); /* superset of */ + map.put((char)8836, "nsub"); /* not a subset of */ + map.put((char)8838, "sube"); /* subset of or equal to */ + map.put((char)8839, "supe"); /* superset of or equal to */ + map.put((char)8853, "oplus"); /* circled plus */ + map.put((char)8855, "otimes"); /* circled times */ + map.put((char)8869, "perp"); /* up tack */ + map.put((char)8901, "sdot"); /* dot operator */ + map.put((char)8968, "lceil"); /* left ceiling */ + map.put((char)8969, "rceil"); /* right ceiling */ + map.put((char)8970, "lfloor"); /* left floor */ + map.put((char)8971, "rfloor"); /* right floor */ + map.put((char)9001, "lang"); /* left-pointing angle bracket */ + map.put((char)9002, "rang"); /* right-pointing angle bracket */ + map.put((char)9674, "loz"); /* lozenge */ + map.put((char)9824, "spades"); /* black spade suit */ + map.put((char)9827, "clubs"); /* black club suit */ + map.put((char)9829, "hearts"); /* black heart suit */ + map.put((char)9830, "diams"); /* black diamond suit */ - return Collections.unmodifiableMap(map); - } + return Collections.unmodifiableMap(map); + } - /** - * Build a unmodifiable Trie from entitiy Name to Character - * @return Unmodifiable trie. - */ - private static synchronized Trie mkEntityToCharacterTrie() - { - Trie trie = new HashTrie(); + /** + * Build a unmodifiable Trie from entitiy Name to Character + * @return Unmodifiable trie. + */ + private static synchronized Trie mkEntityToCharacterTrie() + { + Trie trie = new HashTrie(); - for(Map.Entry entry : characterToEntityMap.entrySet()) - trie.put(entry.getValue(),entry.getKey()); - return Trie.Util.unmodifiable(trie); - } + for(Map.Entry entry : characterToEntityMap.entrySet()) + trie.put(entry.getValue(),entry.getKey()); + return Trie.Util.unmodifiable(trie); + } } diff --git a/src/main/java/org/owasp/esapi/codecs/MySQLCodec.java b/src/main/java/org/owasp/esapi/codecs/MySQLCodec.java index bdcf26a5c..a97f68431 100644 --- a/src/main/java/org/owasp/esapi/codecs/MySQLCodec.java +++ b/src/main/java/org/owasp/esapi/codecs/MySQLCodec.java @@ -94,22 +94,22 @@ static Mode findByKey(int key) { * https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html#sqlmode_ansi_quotes */ public static final int ANSI_MODE = 1; - - //private int mode = 0; + + //private int mode = 0; private Mode mode; - - /** - * Instantiate the MySQL codec - * - * @param mode - * Mode has to be one of {MYSQL_MODE|ANSI_MODE} to allow correct encoding + + /** + * Instantiate the MySQL codec + * + * @param mode + * Mode has to be one of {MYSQL_MODE|ANSI_MODE} to allow correct encoding * @deprecated * @see #MySQLCodec(org.owasp.esapi.codecs.MySQLCodec.Mode) - */ + */ @Deprecated - public MySQLCodec( int mode ) { - this.mode = Mode.findByKey(mode); - } + public MySQLCodec( int mode ) { + this.mode = Mode.findByKey(mode); + } /** * Instantiate the MySQL Codec with the given SQL {@link Mode}. @@ -120,182 +120,182 @@ public MySQLCodec( Mode mode ) { } - /** - * {@inheritDoc} + /** + * {@inheritDoc} */ - public String encodeCharacter( char[] immune, Character c ) { - char ch = c.charValue(); - - // check for immune characters - if ( containsCharacter( ch, immune ) ) { - return ""+ch; - } - - // check for alphanumeric characters - String hex = super.getHexForNonAlphanumeric( ch ); - if ( hex == null ) { - return ""+ch; - } - - - switch( mode ) { - case ANSI: return encodeCharacterANSI( c ); - case STANDARD: return encodeCharacterMySQL( c ); - default: return null; - } - } - - /** - * encodeCharacterANSI encodes for ANSI SQL. - * - * Apostrophe is encoded + public String encodeCharacter( char[] immune, Character c ) { + char ch = c.charValue(); + + // check for immune characters + if ( containsCharacter( ch, immune ) ) { + return ""+ch; + } + + // check for alphanumeric characters + String hex = super.getHexForNonAlphanumeric( ch ); + if ( hex == null ) { + return ""+ch; + } + + + switch( mode ) { + case ANSI: return encodeCharacterANSI( c ); + case STANDARD: return encodeCharacterMySQL( c ); + default: return null; + } + } + + /** + * encodeCharacterANSI encodes for ANSI SQL. + * + * Apostrophe is encoded * * Bug ###: In ANSI Mode Strings can also be passed in using the quotation. In ANSI_QUOTES mode a quotation * is considered to be an identifier, thus cannot be used at all in a value and will be dropped completely. - * - * @param c - * character to encode - * @return - * String encoded to standards of MySQL running in ANSI mode - */ - private String encodeCharacterANSI( Character c ) { - if ( c == '\'' ) - return "\'\'"; + * + * @param c + * character to encode + * @return + * String encoded to standards of MySQL running in ANSI mode + */ + private String encodeCharacterANSI( Character c ) { + if ( c == '\'' ) + return "\'\'"; return ""+c; - } + } - /** - * Encode a character suitable for MySQL - * - * @param c - * Character to encode - * @return - * Encoded Character - */ - private String encodeCharacterMySQL( Character c ) { - char ch = c.charValue(); - if ( ch == 0x00 ) return "\\0"; - if ( ch == 0x08 ) return "\\b"; - if ( ch == 0x09 ) return "\\t"; - if ( ch == 0x0a ) return "\\n"; - if ( ch == 0x0d ) return "\\r"; - if ( ch == 0x1a ) return "\\Z"; - if ( ch == 0x22 ) return "\\\""; - if ( ch == 0x25 ) return "\\%"; - if ( ch == 0x27 ) return "\\'"; - if ( ch == 0x5c ) return "\\\\"; - if ( ch == 0x5f ) return "\\_"; - return "\\" + c; - } - - /** - * {@inheritDoc} - * - * Returns the decoded version of the character starting at index, or - * null if no decoding is possible. - * - * Formats all are legal (case sensitive) - * In ANSI_MODE '' decodes to ' - * In MYSQL_MODE \x decodes to x (or a small list of specials) - */ - public Character decodeCharacter( PushbackSequence input ) { - switch( mode ) { - case ANSI: return decodeCharacterANSI( input ); - case STANDARD: return decodeCharacterMySQL( input ); - default: return null; - } - } + /** + * Encode a character suitable for MySQL + * + * @param c + * Character to encode + * @return + * Encoded Character + */ + private String encodeCharacterMySQL( Character c ) { + char ch = c.charValue(); + if ( ch == 0x00 ) return "\\0"; + if ( ch == 0x08 ) return "\\b"; + if ( ch == 0x09 ) return "\\t"; + if ( ch == 0x0a ) return "\\n"; + if ( ch == 0x0d ) return "\\r"; + if ( ch == 0x1a ) return "\\Z"; + if ( ch == 0x22 ) return "\\\""; + if ( ch == 0x25 ) return "\\%"; + if ( ch == 0x27 ) return "\\'"; + if ( ch == 0x5c ) return "\\\\"; + if ( ch == 0x5f ) return "\\_"; + return "\\" + c; + } + + /** + * {@inheritDoc} + * + * Returns the decoded version of the character starting at index, or + * null if no decoding is possible. + * + * Formats all are legal (case sensitive) + * In ANSI_MODE '' decodes to ' + * In MYSQL_MODE \x decodes to x (or a small list of specials) + */ + public Character decodeCharacter( PushbackSequence input ) { + switch( mode ) { + case ANSI: return decodeCharacterANSI( input ); + case STANDARD: return decodeCharacterMySQL( input ); + default: return null; + } + } - /** - * decodeCharacterANSI decodes the next character from ANSI SQL escaping - * - * @param input - * A PushBackString containing characters you'd like decoded - * @return - * A single character, decoded - */ - private Character decodeCharacterANSI( PushbackSequence input ) { - input.mark(); - Character first = input.next(); - if ( first == null ) { - input.reset(); - return null; - } - - // if this is not an encoded character, return null - if ( first.charValue() != '\'' ) { - input.reset(); - return null; - } + /** + * decodeCharacterANSI decodes the next character from ANSI SQL escaping + * + * @param input + * A PushBackString containing characters you'd like decoded + * @return + * A single character, decoded + */ + private Character decodeCharacterANSI( PushbackSequence input ) { + input.mark(); + Character first = input.next(); + if ( first == null ) { + input.reset(); + return null; + } + + // if this is not an encoded character, return null + if ( first.charValue() != '\'' ) { + input.reset(); + return null; + } - Character second = input.next(); - if ( second == null ) { - input.reset(); - return null; - } - - // if this is not an encoded character, return null - if ( second.charValue() != '\'' ) { - input.reset(); - return null; - } - return( Character.valueOf( '\'' ) ); - } + Character second = input.next(); + if ( second == null ) { + input.reset(); + return null; + } + + // if this is not an encoded character, return null + if ( second.charValue() != '\'' ) { + input.reset(); + return null; + } + return( Character.valueOf( '\'' ) ); + } - /** - * decodeCharacterMySQL decodes all the potential escaped characters that MySQL is prepared to escape - * - * @param input - * A string you'd like to be decoded - * @return - * A single character from that string, decoded. - */ - private Character decodeCharacterMySQL( PushbackSequence input ) { - input.mark(); - Character first = input.next(); - if ( first == null ) { - input.reset(); - return null; - } - - // if this is not an encoded character, return null - if ( first.charValue() != '\\' ) { - input.reset(); - return null; - } + /** + * decodeCharacterMySQL decodes all the potential escaped characters that MySQL is prepared to escape + * + * @param input + * A string you'd like to be decoded + * @return + * A single character from that string, decoded. + */ + private Character decodeCharacterMySQL( PushbackSequence input ) { + input.mark(); + Character first = input.next(); + if ( first == null ) { + input.reset(); + return null; + } + + // if this is not an encoded character, return null + if ( first.charValue() != '\\' ) { + input.reset(); + return null; + } - Character second = input.next(); - if ( second == null ) { - input.reset(); - return null; - } - - if ( second.charValue() == '0' ) { - return Character.valueOf( (char)0x00 ); - } else if ( second.charValue() == 'b' ) { - return Character.valueOf( (char)0x08 ); - } else if ( second.charValue() == 't' ) { - return Character.valueOf( (char)0x09 ); - } else if ( second.charValue() == 'n' ) { - return Character.valueOf( (char)0x0a ); - } else if ( second.charValue() == 'r' ) { - return Character.valueOf( (char)0x0d ); - } else if ( second.charValue() == 'Z' ) { - return Character.valueOf( (char)0x1a ); - } else if ( second.charValue() == '\"' ) { - return Character.valueOf( (char)0x22 ); - } else if ( second.charValue() == '%' ) { - return Character.valueOf( (char)0x25 ); - } else if ( second.charValue() == '\'' ) { - return Character.valueOf( (char)0x27 ); - } else if ( second.charValue() == '\\' ) { - return Character.valueOf( (char)0x5c ); - } else if ( second.charValue() == '_' ) { - return Character.valueOf( (char)0x5f ); - } else { - return second; - } - } + Character second = input.next(); + if ( second == null ) { + input.reset(); + return null; + } + + if ( second.charValue() == '0' ) { + return Character.valueOf( (char)0x00 ); + } else if ( second.charValue() == 'b' ) { + return Character.valueOf( (char)0x08 ); + } else if ( second.charValue() == 't' ) { + return Character.valueOf( (char)0x09 ); + } else if ( second.charValue() == 'n' ) { + return Character.valueOf( (char)0x0a ); + } else if ( second.charValue() == 'r' ) { + return Character.valueOf( (char)0x0d ); + } else if ( second.charValue() == 'Z' ) { + return Character.valueOf( (char)0x1a ); + } else if ( second.charValue() == '\"' ) { + return Character.valueOf( (char)0x22 ); + } else if ( second.charValue() == '%' ) { + return Character.valueOf( (char)0x25 ); + } else if ( second.charValue() == '\'' ) { + return Character.valueOf( (char)0x27 ); + } else if ( second.charValue() == '\\' ) { + return Character.valueOf( (char)0x5c ); + } else if ( second.charValue() == '_' ) { + return Character.valueOf( (char)0x5f ); + } else { + return second; + } + } } diff --git a/src/main/java/org/owasp/esapi/codecs/OracleCodec.java b/src/main/java/org/owasp/esapi/codecs/OracleCodec.java index 0021a8613..5a5db7d67 100644 --- a/src/main/java/org/owasp/esapi/codecs/OracleCodec.java +++ b/src/main/java/org/owasp/esapi/codecs/OracleCodec.java @@ -33,58 +33,58 @@ public class OracleCodec extends AbstractCharacterCodec { - /** - * {@inheritDoc} - * - * Encodes ' to '' + /** + * {@inheritDoc} + * + * Encodes ' to '' * - * Encodes ' to '' + * Encodes ' to '' * * @param immune */ - public String encodeCharacter( char[] immune, Character c ) { - if ( c.charValue() == '\'' ) - return "\'\'"; + public String encodeCharacter( char[] immune, Character c ) { + if ( c.charValue() == '\'' ) + return "\'\'"; return ""+c; - } - + } + - /** - * {@inheritDoc} - * - * Returns the decoded version of the character starting at index, or - * null if no decoding is possible. - * - * Formats all are legal - * '' decodes to ' - */ - public Character decodeCharacter( PushbackSequence input ) { - input.mark(); - Character first = input.next(); - if ( first == null ) { - input.reset(); - return null; - } + /** + * {@inheritDoc} + * + * Returns the decoded version of the character starting at index, or + * null if no decoding is possible. + * + * Formats all are legal + * '' decodes to ' + */ + public Character decodeCharacter( PushbackSequence input ) { + input.mark(); + Character first = input.next(); + if ( first == null ) { + input.reset(); + return null; + } - // if this is not an encoded character, return null - if ( first.charValue() != '\'' ) { - input.reset(); - return null; - } + // if this is not an encoded character, return null + if ( first.charValue() != '\'' ) { + input.reset(); + return null; + } - Character second = input.next(); - if ( second == null ) { - input.reset(); - return null; - } - - // if this is not an encoded character, return null - if ( second.charValue() != '\'' ) { - input.reset(); - return null; - } - return( Character.valueOf( '\'' ) ); - } + Character second = input.next(); + if ( second == null ) { + input.reset(); + return null; + } + + // if this is not an encoded character, return null + if ( second.charValue() != '\'' ) { + input.reset(); + return null; + } + return( Character.valueOf( '\'' ) ); + } } \ No newline at end of file diff --git a/src/main/java/org/owasp/esapi/codecs/PercentCodec.java b/src/main/java/org/owasp/esapi/codecs/PercentCodec.java index ac9e9a59e..38a1ea8f4 100644 --- a/src/main/java/org/owasp/esapi/codecs/PercentCodec.java +++ b/src/main/java/org/owasp/esapi/codecs/PercentCodec.java @@ -30,135 +30,135 @@ */ public class PercentCodec extends AbstractCharacterCodec { - private static final String ALPHA_NUMERIC_STR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - @SuppressWarnings("unused") - private static final String RFC3986_RESERVED_STR = ":/?#[]@!$&'()*+,;="; - private static final String RFC3986_NON_ALPHANUMERIC_UNRESERVED_STR = "-._~"; - // rfc3986 2.3: For consistency, percent-encoded octets - // in the ranges of ALPHA (%41-%5A and %61-%7A), DIGIT - // (%30-%39), hyphen (%2D), period (%2E), underscore - // (%5F), or tilde (%7E) should not be created by URI - // producers - private static final boolean ENCODED_NON_ALPHA_NUMERIC_UNRESERVED = true; - private static final String UNENCODED_STR = ALPHA_NUMERIC_STR + - (ENCODED_NON_ALPHA_NUMERIC_UNRESERVED ? "" : RFC3986_NON_ALPHANUMERIC_UNRESERVED_STR); - private static final Set UNENCODED_SET = CollectionsUtil.strToUnmodifiableSet(UNENCODED_STR); + private static final String ALPHA_NUMERIC_STR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + @SuppressWarnings("unused") + private static final String RFC3986_RESERVED_STR = ":/?#[]@!$&'()*+,;="; + private static final String RFC3986_NON_ALPHANUMERIC_UNRESERVED_STR = "-._~"; + // rfc3986 2.3: For consistency, percent-encoded octets + // in the ranges of ALPHA (%41-%5A and %61-%7A), DIGIT + // (%30-%39), hyphen (%2D), period (%2E), underscore + // (%5F), or tilde (%7E) should not be created by URI + // producers + private static final boolean ENCODED_NON_ALPHA_NUMERIC_UNRESERVED = true; + private static final String UNENCODED_STR = ALPHA_NUMERIC_STR + + (ENCODED_NON_ALPHA_NUMERIC_UNRESERVED ? "" : RFC3986_NON_ALPHANUMERIC_UNRESERVED_STR); + private static final Set UNENCODED_SET = CollectionsUtil.strToUnmodifiableSet(UNENCODED_STR); - /** - * Convinence method to encode a string into UTF-8. This - * wraps the {@link UnsupportedEncodingException} that - * {@link String#getBytes(String)} throws in a - * {@link IllegalStateException} as UTF-8 support is required - * by the Java spec and should never throw this exception. - * @param str the string to encode - * @return str encoded in UTF-8 as bytes. - * @throws IllegalStateException wrapped {@link - * UnsupportedEncodingException} if - * {@link String.getBytes(String)} throws it. - */ - private static byte[] toUtf8Bytes(String str) - { - try - { - return str.getBytes("UTF-8"); - } - catch(UnsupportedEncodingException e) - { - throw new IllegalStateException("The Java spec requires UTF-8 support.", e); - } - } + /** + * Convinence method to encode a string into UTF-8. This + * wraps the {@link UnsupportedEncodingException} that + * {@link String#getBytes(String)} throws in a + * {@link IllegalStateException} as UTF-8 support is required + * by the Java spec and should never throw this exception. + * @param str the string to encode + * @return str encoded in UTF-8 as bytes. + * @throws IllegalStateException wrapped {@link + * UnsupportedEncodingException} if + * {@link String.getBytes(String)} throws it. + */ + private static byte[] toUtf8Bytes(String str) + { + try + { + return str.getBytes("UTF-8"); + } + catch(UnsupportedEncodingException e) + { + throw new IllegalStateException("The Java spec requires UTF-8 support.", e); + } + } - /** - * Append the two upper case hex characters for a byte. - * @param sb The string buffer to append to. - * @param b The byte to hexify - * @return sb with the hex characters appended. - */ - // rfc3986 2.1: For consistency, URI producers - // should use uppercase hexadecimal digits for all percent- - // encodings. - private static StringBuilder appendTwoUpperHex(StringBuilder sb, int b) - { - if(b < Byte.MIN_VALUE || b > Byte.MAX_VALUE) - throw new IllegalArgumentException("b is not a byte (was " + b + ')'); - b &= 0xFF; - if(b<0x10) - sb.append('0'); - return sb.append(Integer.toHexString(b).toUpperCase()); - } + /** + * Append the two upper case hex characters for a byte. + * @param sb The string buffer to append to. + * @param b The byte to hexify + * @return sb with the hex characters appended. + */ + // rfc3986 2.1: For consistency, URI producers + // should use uppercase hexadecimal digits for all percent- + // encodings. + private static StringBuilder appendTwoUpperHex(StringBuilder sb, int b) + { + if(b < Byte.MIN_VALUE || b > Byte.MAX_VALUE) + throw new IllegalArgumentException("b is not a byte (was " + b + ')'); + b &= 0xFF; + if(b<0x10) + sb.append('0'); + return sb.append(Integer.toHexString(b).toUpperCase()); + } - /** - * Encode a character for URLs - * @param immune Additional characters not to encode. Note this could + /** + * Encode a character for URLs + * @param immune Additional characters not to encode. Note this could * break URL encoding as referenced in RFC 3986. You should * especially be wary of including '%' in this list of immune * characters since it is used as the "escape" character for * the hex encoding and including it may result in subsequent * and/or dangerous results when decoding. - * @param c character to encode - * @return the encoded string representing c - */ - public String encodeCharacter( char[] immune, Character c ) - { - String cStr = String.valueOf(c.charValue()); - byte[] bytes; - StringBuilder sb; + * @param c character to encode + * @return the encoded string representing c + */ + public String encodeCharacter( char[] immune, Character c ) + { + String cStr = String.valueOf(c.charValue()); + byte[] bytes; + StringBuilder sb; // check for user specified immune characters if ( immune != null && containsCharacter( c.charValue(), immune ) ) return cStr; // check for standard characters (e.g., alphanumeric, etc.) - if(UNENCODED_SET.contains(c)) - return cStr; + if(UNENCODED_SET.contains(c)) + return cStr; - bytes = toUtf8Bytes(cStr); - sb = new StringBuilder(bytes.length * 3); - for(byte b : bytes) - appendTwoUpperHex(sb.append('%'), b); - return sb.toString(); - } + bytes = toUtf8Bytes(cStr); + sb = new StringBuilder(bytes.length * 3); + for(byte b : bytes) + appendTwoUpperHex(sb.append('%'), b); + return sb.toString(); + } - /** - * {@inheritDoc} - * - * Formats all are legal both upper/lower case: - * %hh; - * - * @param input - * encoded character using percent characters (such as URL encoding) - */ - public Character decodeCharacter( PushbackSequence input ) { - input.mark(); - Character first = input.next(); - if ( first == null ) { - input.reset(); - return null; - } + /** + * {@inheritDoc} + * + * Formats all are legal both upper/lower case: + * %hh; + * + * @param input + * encoded character using percent characters (such as URL encoding) + */ + public Character decodeCharacter( PushbackSequence input ) { + input.mark(); + Character first = input.next(); + if ( first == null ) { + input.reset(); + return null; + } - // if this is not an encoded character, return null - if (first != '%' ) { - input.reset(); - return null; - } + // if this is not an encoded character, return null + if (first != '%' ) { + input.reset(); + return null; + } - // Search for exactly 2 hex digits following - StringBuilder sb = new StringBuilder(); - for ( int i=0; i<2; i++ ) { - Character c = input.nextHex(); - if ( c != null ) sb.append( c ); - } - if ( sb.length() == 2 ) { - try { - // parse the hex digit and create a character - int i = Integer.parseInt(sb.toString(), 16); - if (Character.isValidCodePoint(i)) { - return (char) i; - } - } catch( NumberFormatException ignored ) { } - } - input.reset(); - return null; - } + // Search for exactly 2 hex digits following + StringBuilder sb = new StringBuilder(); + for ( int i=0; i<2; i++ ) { + Character c = input.nextHex(); + if ( c != null ) sb.append( c ); + } + if ( sb.length() == 2 ) { + try { + // parse the hex digit and create a character + int i = Integer.parseInt(sb.toString(), 16); + if (Character.isValidCodePoint(i)) { + return (char) i; + } + } catch( NumberFormatException ignored ) { } + } + input.reset(); + return null; + } } diff --git a/src/main/java/org/owasp/esapi/codecs/PushBackSequenceImpl.java b/src/main/java/org/owasp/esapi/codecs/PushBackSequenceImpl.java index adfa9e898..7b858badd 100644 --- a/src/main/java/org/owasp/esapi/codecs/PushBackSequenceImpl.java +++ b/src/main/java/org/owasp/esapi/codecs/PushBackSequenceImpl.java @@ -16,121 +16,121 @@ public class PushBackSequenceImpl extends AbstractPushbackSequence{ * @param input */ public PushBackSequenceImpl( String input ) { - super(input); - } - + super(input); + } + /** * * @return The next value in this Sequence, as an Integer. */ public Integer next() { - if ( pushback != null ) { - Integer save = pushback; - pushback = null; - return save; - } - if ( input == null ) return null; - if ( input.length() == 0 ) return null; - if ( index >= input.length() ) return null; - final Integer point = input.codePointAt(index); - index += Character.charCount(point); - return point; - } - + if ( pushback != null ) { + Integer save = pushback; + pushback = null; + return save; + } + if ( input == null ) return null; + if ( input.length() == 0 ) return null; + if ( index >= input.length() ) return null; + final Integer point = input.codePointAt(index); + index += Character.charCount(point); + return point; + } + /** * * @return The next value in this Sequence, as an Integer if it is a hex digit. Null otherwise. */ public Integer nextHex() { - Integer c = next(); - if ( c == null ) return null; - if ( isHexDigit( c ) ) return c; - return null; - } + Integer c = next(); + if ( c == null ) return null; + if ( isHexDigit( c ) ) return c; + return null; + } /** * * @return The next value in this Sequence, as an Integer if it is an octal digit. Null otherwise. */ public Integer nextOctal() { - Integer c = next(); - if ( c == null ) return null; - if ( isOctalDigit( c ) ) return c; - return null; - } + Integer c = next(); + if ( c == null ) return null; + if ( isOctalDigit( c ) ) return c; + return null; + } - /** - * Returns true if the parameter character is a hexidecimal digit 0 through 9, a through f, or A through F. - * @param c - * @return true if it is a hexidecimal digit, false otherwise. - */ - public static boolean isHexDigit( Integer c ) { - if ( c == null ) return false; - Integer ch = Integer.valueOf(c); - return (ch >= '0' && ch <= '9' ) || (ch >= 'a' && ch <= 'f' ) || (ch >= 'A' && ch <= 'F' ); - } + /** + * Returns true if the parameter character is a hexidecimal digit 0 through 9, a through f, or A through F. + * @param c + * @return true if it is a hexidecimal digit, false otherwise. + */ + public static boolean isHexDigit( Integer c ) { + if ( c == null ) return false; + Integer ch = Integer.valueOf(c); + return (ch >= '0' && ch <= '9' ) || (ch >= 'a' && ch <= 'f' ) || (ch >= 'A' && ch <= 'F' ); + } - /** - * Returns true if the parameter character is an octal digit 0 through 7. - * @param c - * @return true if it is an octal digit, false otherwise. - */ - public static boolean isOctalDigit( Integer c ) { - if ( c == null ) return false; - Integer ch = Integer.valueOf(c); - return ch >= '0' && ch <= '7'; - } + /** + * Returns true if the parameter character is an octal digit 0 through 7. + * @param c + * @return true if it is an octal digit, false otherwise. + */ + public static boolean isOctalDigit( Integer c ) { + if ( c == null ) return false; + Integer ch = Integer.valueOf(c); + return ch >= '0' && ch <= '7'; + } /** * Return the next codePoint without affecting the current index. * @return the next codePoint */ public Integer peek() { - if ( pushback != null ) return pushback; - if ( input == null ) return null; - if ( input.length() == 0 ) return null; - if ( index >= input.length() ) return null; - return input.codePointAt(index); - } - + if ( pushback != null ) return pushback; + if ( input == null ) return null; + if ( input.length() == 0 ) return null; + if ( index >= input.length() ) return null; + return input.codePointAt(index); + } + /** * Test to see if the next codePoint is a particular value without affecting the current index. * @param c * @return if the next value is equal to the supplied value. */ public boolean peek( Integer c ) { - if ( pushback != null && pushback.intValue() == c ) return true; - if ( input == null ) return false; - if ( input.length() == 0 ) return false; - if ( index >= input.length() ) return false; - return input.codePointAt(index) == c; - } - + if ( pushback != null && pushback.intValue() == c ) return true; + if ( input == null ) return false; + if ( input.length() == 0 ) return false; + if ( index >= input.length() ) return false; + return input.codePointAt(index) == c; + } + /** * {@inheritDoc} */ public void mark() { - temp = pushback; - mark = index; - } + temp = pushback; + mark = index; + } /** * {@inheritDoc} */ public void reset() { - pushback = temp; - index = mark; - } - + pushback = temp; + index = mark; + } + /** * {@inheritDoc} */ public String remainder() { - String output = input.substring( index ); - if ( pushback != null ) { - output = pushback + output; - } - return output; - } + String output = input.substring( index ); + if ( pushback != null ) { + output = pushback + output; + } + return output; + } } diff --git a/src/main/java/org/owasp/esapi/codecs/PushbackSequence.java b/src/main/java/org/owasp/esapi/codecs/PushbackSequence.java index e3aab4d07..dfdc61e12 100644 --- a/src/main/java/org/owasp/esapi/codecs/PushbackSequence.java +++ b/src/main/java/org/owasp/esapi/codecs/PushbackSequence.java @@ -18,72 +18,72 @@ public interface PushbackSequence { - /** - * - * @param c - */ - void pushback(T c); + /** + * + * @param c + */ + void pushback(T c); - /** - * Get the current index of the PushbackString. Typically used in error messages. - * @return The current index of the PushbackSequence. - */ - int index(); + /** + * Get the current index of the PushbackString. Typically used in error messages. + * @return The current index of the PushbackSequence. + */ + int index(); - /** - * Determine if this sequence has another element. - * - * @return True if there is another element in this sequence. False otherwise. - */ - boolean hasNext(); + /** + * Determine if this sequence has another element. + * + * @return True if there is another element in this sequence. False otherwise. + */ + boolean hasNext(); - /** - * Return the next element in the Sequence and increment the current index. - * @return The next element in the Sequence. - */ - T next(); + /** + * Return the next element in the Sequence and increment the current index. + * @return The next element in the Sequence. + */ + T next(); - /** - * Return the next element in the Sequence in Hex format and increment the current index. - * @return The next element in the Sequence in Hex format (if that makes sense for this Sequence's type). + /** + * Return the next element in the Sequence in Hex format and increment the current index. + * @return The next element in the Sequence in Hex format (if that makes sense for this Sequence's type). */ - T nextHex(); + T nextHex(); - /** - * Return the next element in the Sequence in Octal format and increment the current index. - * @return The next element in the Sequence in Octal format (if that makes sense for this Sequence's type). - */ - T nextOctal(); + /** + * Return the next element in the Sequence in Octal format and increment the current index. + * @return The next element in the Sequence in Octal format (if that makes sense for this Sequence's type). + */ + T nextOctal(); - /** - * Return the next element in the Sequence without affecting the current index. - * @return the next element in the Sequence. - */ - T peek(); + /** + * Return the next element in the Sequence without affecting the current index. + * @return the next element in the Sequence. + */ + T peek(); - /** - * Test to see if the next element in the Sequence matches the supplied value without affecting the current index. - * @param c The value to match against. - * @return True if the next element matches the supplied value. False otherwise. - */ - boolean peek(T c); + /** + * Test to see if the next element in the Sequence matches the supplied value without affecting the current index. + * @param c The value to match against. + * @return True if the next element matches the supplied value. False otherwise. + */ + boolean peek(T c); - /** - * Mark the location of the current index. - */ - void mark(); + /** + * Mark the location of the current index. + */ + void mark(); - /** - * Set the index back to the last marked location. - */ - void reset(); + /** + * Set the index back to the last marked location. + */ + void reset(); - /** - * Not at all sure what this method is intended to do. There - * is a line in HTMLEntityCodec that said calling this method - * is a "kludge around PushbackString..." - * @return Return the remaining portion of the sequence, with any pushback appended to the front (if any). - */ - String remainder(); + /** + * Not at all sure what this method is intended to do. There + * is a line in HTMLEntityCodec that said calling this method + * is a "kludge around PushbackString..." + * @return Return the remaining portion of the sequence, with any pushback appended to the front (if any). + */ + String remainder(); } \ No newline at end of file diff --git a/src/main/java/org/owasp/esapi/codecs/PushbackString.java b/src/main/java/org/owasp/esapi/codecs/PushbackString.java index fb133b54c..96bdec5ab 100644 --- a/src/main/java/org/owasp/esapi/codecs/PushbackString.java +++ b/src/main/java/org/owasp/esapi/codecs/PushbackString.java @@ -31,193 +31,193 @@ */ public class PushbackString extends AbstractPushbackSequence { - /** + /** * @param input Construct a PushbackString with the specified String. - */ - public PushbackString(String input) { - super(input); - } + */ + public PushbackString(String input) { + super(input); + } - /* - * (non-Javadoc) - * - * @see org.owasp.esapi.codecs.PushbackSequence#index() - */ - public int index() { - return index; - } + /* + * (non-Javadoc) + * + * @see org.owasp.esapi.codecs.PushbackSequence#index() + */ + public int index() { + return index; + } - /* - * (non-Javadoc) - * - * @see org.owasp.esapi.codecs.PushbackSequence#hasNext() - */ - public boolean hasNext() { - if (pushback != null){ - return true; - } - if (input == null){ - return false; - } - if (input.length() == 0){ - return false; - } - if (index >= input.length()){ - return false; - } - return true; - } + /* + * (non-Javadoc) + * + * @see org.owasp.esapi.codecs.PushbackSequence#hasNext() + */ + public boolean hasNext() { + if (pushback != null){ + return true; + } + if (input == null){ + return false; + } + if (input.length() == 0){ + return false; + } + if (index >= input.length()){ + return false; + } + return true; + } - /* - * (non-Javadoc) - * - * @see org.owasp.esapi.codecs.PushbackSequence#next() - */ - public Character next() { - if (pushback != null) { - Character save = pushback; - pushback = null; - return save; - } - if (input == null){ - return null; - } - if (input.length() == 0){ - return null; - } - if (index >= input.length()){ - return null; - } - return Character.valueOf(input.charAt(index++)); - } + /* + * (non-Javadoc) + * + * @see org.owasp.esapi.codecs.PushbackSequence#next() + */ + public Character next() { + if (pushback != null) { + Character save = pushback; + pushback = null; + return save; + } + if (input == null){ + return null; + } + if (input.length() == 0){ + return null; + } + if (index >= input.length()){ + return null; + } + return Character.valueOf(input.charAt(index++)); + } - /* - * (non-Javadoc) - * - * @see org.owasp.esapi.codecs.PushbackSequence#nextHex() - */ - public Character nextHex() { - Character c = next(); - if (c == null){ - return null; - } - if (isHexDigit(c)){ - return c; - } - return null; - } + /* + * (non-Javadoc) + * + * @see org.owasp.esapi.codecs.PushbackSequence#nextHex() + */ + public Character nextHex() { + Character c = next(); + if (c == null){ + return null; + } + if (isHexDigit(c)){ + return c; + } + return null; + } - /* - * (non-Javadoc) - * - * @see org.owasp.esapi.codecs.PushbackSequence#nextOctal() - */ - public Character nextOctal() { - Character c = next(); - if (c == null){ - return null; - } - if (isOctalDigit(c)){ - return c; - } - return null; - } + /* + * (non-Javadoc) + * + * @see org.owasp.esapi.codecs.PushbackSequence#nextOctal() + */ + public Character nextOctal() { + Character c = next(); + if (c == null){ + return null; + } + if (isOctalDigit(c)){ + return c; + } + return null; + } - /** - * Returns true if the parameter character is a hexidecimal digit 0 through - * 9, a through f, or A through F. - * - * @param c - * @return true if it is a hexidecimal digit, false otherwise. - */ - public static boolean isHexDigit(Character c) { - if (c == null){ - return false; - } - char ch = c.charValue(); - return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); - } + /** + * Returns true if the parameter character is a hexidecimal digit 0 through + * 9, a through f, or A through F. + * + * @param c + * @return true if it is a hexidecimal digit, false otherwise. + */ + public static boolean isHexDigit(Character c) { + if (c == null){ + return false; + } + char ch = c.charValue(); + return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); + } - /** - * Returns true if the parameter character is an octal digit 0 through 7. - * - * @param c - * @return true if it is an octal digit, false otherwise. - */ - public static boolean isOctalDigit(Character c) { - if (c == null){ - return false; - } - char ch = c.charValue(); - return ch >= '0' && ch <= '7'; - } + /** + * Returns true if the parameter character is an octal digit 0 through 7. + * + * @param c + * @return true if it is an octal digit, false otherwise. + */ + public static boolean isOctalDigit(Character c) { + if (c == null){ + return false; + } + char ch = c.charValue(); + return ch >= '0' && ch <= '7'; + } - /* - * (non-Javadoc) - * - * @see org.owasp.esapi.codecs.PushbackSequence#peek() - */ - public Character peek() { - if (pushback != null){ - return pushback; - } - if (input == null){ - return null; - } - if (input.length() == 0){ - return null; - } - if (index >= input.length()){ - return null; - } - return Character.valueOf(input.charAt(index)); - } + /* + * (non-Javadoc) + * + * @see org.owasp.esapi.codecs.PushbackSequence#peek() + */ + public Character peek() { + if (pushback != null){ + return pushback; + } + if (input == null){ + return null; + } + if (input.length() == 0){ + return null; + } + if (index >= input.length()){ + return null; + } + return Character.valueOf(input.charAt(index)); + } - /* - * (non-Javadoc) - * - * @see org.owasp.esapi.codecs.PushbackSequence#peek(char) - */ - public boolean peek(Character c) { - if (pushback != null && pushback.charValue() == c){ - return true; - } - if (input == null){ - return false; - } - if (input.length() == 0){ - return false; - } - if (index >= input.length()){ - return false; - } - return input.charAt(index) == c; - } + /* + * (non-Javadoc) + * + * @see org.owasp.esapi.codecs.PushbackSequence#peek(char) + */ + public boolean peek(Character c) { + if (pushback != null && pushback.charValue() == c){ + return true; + } + if (input == null){ + return false; + } + if (input.length() == 0){ + return false; + } + if (index >= input.length()){ + return false; + } + return input.charAt(index) == c; + } - /** - * {@inheritDoc} - */ - public void mark() { - temp = pushback; - mark = index; - } + /** + * {@inheritDoc} + */ + public void mark() { + temp = pushback; + mark = index; + } - /** - * {@inheritDoc} - */ - public void reset() { - pushback = temp; - index = mark; - } + /** + * {@inheritDoc} + */ + public void reset() { + pushback = temp; + index = mark; + } - /** - * {@inheritDoc} - */ - public String remainder() { - String output = input.substring(index); - if (pushback != null) { - output = pushback + output; - } - return output; - } + /** + * {@inheritDoc} + */ + public String remainder() { + String output = input.substring(index); + if (pushback != null) { + output = pushback + output; + } + return output; + } } \ No newline at end of file diff --git a/src/main/java/org/owasp/esapi/codecs/Trie.java b/src/main/java/org/owasp/esapi/codecs/Trie.java index da11268d3..fbb8c99ec 100644 --- a/src/main/java/org/owasp/esapi/codecs/Trie.java +++ b/src/main/java/org/owasp/esapi/codecs/Trie.java @@ -9,164 +9,164 @@ public interface Trie extends Map { - public Map.Entry getLongestMatch(CharSequence key); - public Map.Entry getLongestMatch(PushbackReader keyIn) throws IOException; - public int getMaxKeyLength(); - - static class TrieProxy implements Trie - { - private Trie wrapped; - - TrieProxy(Trie toWrap) - { - wrapped = toWrap; - } - - protected Trie getWrapped() - { - return wrapped; - } - - public Map.Entry getLongestMatch(CharSequence key) - { - return wrapped.getLongestMatch(key); - } - - public Map.Entry getLongestMatch(PushbackReader keyIn) throws IOException - { - return wrapped.getLongestMatch(keyIn); - } - - public int getMaxKeyLength() - { - return wrapped.getMaxKeyLength(); - } - - /* java.util.Map: */ - - public int size() - { - return wrapped.size(); - } - - public boolean isEmpty() - { - return wrapped.isEmpty(); - } - - public boolean containsKey(Object key) - { - return wrapped.containsKey(key); - } - - public boolean containsValue(Object val) - { - return wrapped.containsValue(val); - } - - public T get(Object key) - { - return wrapped.get(key); - } - - public T put(CharSequence key, T value) - { - return wrapped.put(key, value); - } - - public T remove(Object key) - { - return wrapped.remove(key); - } - - public void putAll(Map t) - { - wrapped.putAll(t); - } - - public void clear() - { - wrapped.clear(); - } - - public Set keySet() - { - return wrapped.keySet(); - } - - public Collection values() - { - return wrapped.values(); - } - - public Set> entrySet() - { - return wrapped.entrySet(); - } - - public boolean equals(Object other) - { - return wrapped.equals(other); - } - - public int hashCode() - { - return wrapped.hashCode(); - } - } - - static class Unmodifiable extends TrieProxy - { - Unmodifiable(Trie toWrap) - { - super(toWrap); - } - - public T put(CharSequence key, T value) - { - throw new UnsupportedOperationException("Unmodifiable Trie"); - } - - public T remove(CharSequence key) - { - throw new UnsupportedOperationException("Unmodifiable Trie"); - } - - public void putAll(Map t) - { - throw new UnsupportedOperationException("Unmodifiable Trie"); - } - - public void clear() - { - throw new UnsupportedOperationException("Unmodifiable Trie"); - } - - public Set keySet() - { - return Collections.unmodifiableSet(super.keySet()); - } - - public Collection values() - { - return Collections.unmodifiableCollection(super.values()); - } - - public Set> entrySet() - { - return Collections.unmodifiableSet(super.entrySet()); - } - } - - public static class Util - { - private Util() - { - } - - static Trie unmodifiable(Trie toWrap) - { - return new Unmodifiable(toWrap); - } - } + public Map.Entry getLongestMatch(CharSequence key); + public Map.Entry getLongestMatch(PushbackReader keyIn) throws IOException; + public int getMaxKeyLength(); + + static class TrieProxy implements Trie + { + private Trie wrapped; + + TrieProxy(Trie toWrap) + { + wrapped = toWrap; + } + + protected Trie getWrapped() + { + return wrapped; + } + + public Map.Entry getLongestMatch(CharSequence key) + { + return wrapped.getLongestMatch(key); + } + + public Map.Entry getLongestMatch(PushbackReader keyIn) throws IOException + { + return wrapped.getLongestMatch(keyIn); + } + + public int getMaxKeyLength() + { + return wrapped.getMaxKeyLength(); + } + + /* java.util.Map: */ + + public int size() + { + return wrapped.size(); + } + + public boolean isEmpty() + { + return wrapped.isEmpty(); + } + + public boolean containsKey(Object key) + { + return wrapped.containsKey(key); + } + + public boolean containsValue(Object val) + { + return wrapped.containsValue(val); + } + + public T get(Object key) + { + return wrapped.get(key); + } + + public T put(CharSequence key, T value) + { + return wrapped.put(key, value); + } + + public T remove(Object key) + { + return wrapped.remove(key); + } + + public void putAll(Map t) + { + wrapped.putAll(t); + } + + public void clear() + { + wrapped.clear(); + } + + public Set keySet() + { + return wrapped.keySet(); + } + + public Collection values() + { + return wrapped.values(); + } + + public Set> entrySet() + { + return wrapped.entrySet(); + } + + public boolean equals(Object other) + { + return wrapped.equals(other); + } + + public int hashCode() + { + return wrapped.hashCode(); + } + } + + static class Unmodifiable extends TrieProxy + { + Unmodifiable(Trie toWrap) + { + super(toWrap); + } + + public T put(CharSequence key, T value) + { + throw new UnsupportedOperationException("Unmodifiable Trie"); + } + + public T remove(CharSequence key) + { + throw new UnsupportedOperationException("Unmodifiable Trie"); + } + + public void putAll(Map t) + { + throw new UnsupportedOperationException("Unmodifiable Trie"); + } + + public void clear() + { + throw new UnsupportedOperationException("Unmodifiable Trie"); + } + + public Set keySet() + { + return Collections.unmodifiableSet(super.keySet()); + } + + public Collection values() + { + return Collections.unmodifiableCollection(super.values()); + } + + public Set> entrySet() + { + return Collections.unmodifiableSet(super.entrySet()); + } + } + + public static class Util + { + private Util() + { + } + + static Trie unmodifiable(Trie toWrap) + { + return new Unmodifiable(toWrap); + } + } } diff --git a/src/main/java/org/owasp/esapi/codecs/UnixCodec.java b/src/main/java/org/owasp/esapi/codecs/UnixCodec.java index faeebad65..96ed3d7a7 100644 --- a/src/main/java/org/owasp/esapi/codecs/UnixCodec.java +++ b/src/main/java/org/owasp/esapi/codecs/UnixCodec.java @@ -26,57 +26,57 @@ */ public class UnixCodec extends AbstractCharacterCodec { - /** - * {@inheritDoc} - * - * Returns backslash-encoded character + /** + * {@inheritDoc} + * + * Returns backslash-encoded character * * @param immune */ - public String encodeCharacter( char[] immune, Character c ) { - char ch = c.charValue(); - - // check for immune characters - if ( containsCharacter( ch, immune ) ) { - return ""+ch; - } - - // check for alphanumeric characters - String hex = super.getHexForNonAlphanumeric( ch ); - if ( hex == null ) { - return ""+ch; - } - + public String encodeCharacter( char[] immune, Character c ) { + char ch = c.charValue(); + + // check for immune characters + if ( containsCharacter( ch, immune ) ) { + return ""+ch; + } + + // check for alphanumeric characters + String hex = super.getHexForNonAlphanumeric( ch ); + if ( hex == null ) { + return ""+ch; + } + return "\\" + c; - } - - - /** - * {@inheritDoc} - * - * Returns the decoded version of the character starting at index, or - * null if no decoding is possible. - *

    - * Formats all are legal both upper/lower case: - * \x - all special characters - * - */ - public Character decodeCharacter( PushbackSequence input ) { - input.mark(); - Character first = input.next(); - if ( first == null ) { - input.reset(); - return null; - } - - // if this is not an encoded character, return null - if ( first.charValue() != '\\' ) { - input.reset(); - return null; - } + } + + + /** + * {@inheritDoc} + * + * Returns the decoded version of the character starting at index, or + * null if no decoding is possible. + *

    + * Formats all are legal both upper/lower case: + * \x - all special characters + * + */ + public Character decodeCharacter( PushbackSequence input ) { + input.mark(); + Character first = input.next(); + if ( first == null ) { + input.reset(); + return null; + } + + // if this is not an encoded character, return null + if ( first.charValue() != '\\' ) { + input.reset(); + return null; + } - Character second = input.next(); - return second; - } + Character second = input.next(); + return second; + } } \ No newline at end of file diff --git a/src/main/java/org/owasp/esapi/codecs/VBScriptCodec.java b/src/main/java/org/owasp/esapi/codecs/VBScriptCodec.java index 122e90aad..ba9694786 100644 --- a/src/main/java/org/owasp/esapi/codecs/VBScriptCodec.java +++ b/src/main/java/org/owasp/esapi/codecs/VBScriptCodec.java @@ -28,90 +28,90 @@ */ public class VBScriptCodec extends AbstractCharacterCodec { - /** - * Encode a String so that it can be safely used in a specific context. - * + /** + * Encode a String so that it can be safely used in a specific context. + * * @param immune * @param input - * the String to encode - * @return the encoded String - */ + * the String to encode + * @return the encoded String + */ public String encode(char[] immune, String input) { - StringBuilder sb = new StringBuilder(); - boolean encoding = false; - boolean inquotes = false; - for ( int i=0; i 0 ) sb.append( "&" ); - if ( !inquotes && i > 0 ) sb.append( "\"" ); - sb.append( c ); - inquotes = true; - encoding = false; - - // handle characters that need encoding - } else { - if ( inquotes && i < input.length() ) sb.append( "\"" ); - if ( i > 0 ) sb.append( "&" ); - sb.append( encodeCharacter( immune, Character.valueOf( c ) ) ); - inquotes = false; - encoding = true; - } - } - return sb.toString(); + StringBuilder sb = new StringBuilder(); + boolean encoding = false; + boolean inquotes = false; + for ( int i=0; i 0 ) sb.append( "&" ); + if ( !inquotes && i > 0 ) sb.append( "\"" ); + sb.append( c ); + inquotes = true; + encoding = false; + + // handle characters that need encoding + } else { + if ( inquotes && i < input.length() ) sb.append( "\"" ); + if ( i > 0 ) sb.append( "&" ); + sb.append( encodeCharacter( immune, Character.valueOf( c ) ) ); + inquotes = false; + encoding = true; + } + } + return sb.toString(); } - /** - * Returns quote-encoded character + /** + * Returns quote-encoded character * * @param immune */ - public String encodeCharacter( char[] immune, Character c ) { - char ch = c.charValue(); - - // check for immune characters - if ( containsCharacter( ch, immune ) ) { - return ""+ch; - } - - // check for alphanumeric characters - String hex = super.getHexForNonAlphanumeric( ch ); - if ( hex == null ) { - return ""+ch; - } - + public String encodeCharacter( char[] immune, Character c ) { + char ch = c.charValue(); + + // check for immune characters + if ( containsCharacter( ch, immune ) ) { + return ""+ch; + } + + // check for alphanumeric characters + String hex = super.getHexForNonAlphanumeric( ch ); + if ( hex == null ) { + return ""+ch; + } + return "chrw(" + (int)c.charValue() + ")"; - } - - - - /** - * Returns the decoded version of the character starting at index, or - * null if no decoding is possible. - * - * Formats all are legal both upper/lower case: - * "x - all special characters - * " + chr(x) + " - not supported yet - */ - public Character decodeCharacter( PushbackSequence input ) { - input.mark(); - Character first = input.next(); - if ( first == null ) { - input.reset(); - return null; - } - - // if this is not an encoded character, return null - if ( first.charValue() != '\"' ) { - input.reset(); - return null; - } + } + + + + /** + * Returns the decoded version of the character starting at index, or + * null if no decoding is possible. + * + * Formats all are legal both upper/lower case: + * "x - all special characters + * " + chr(x) + " - not supported yet + */ + public Character decodeCharacter( PushbackSequence input ) { + input.mark(); + Character first = input.next(); + if ( first == null ) { + input.reset(); + return null; + } + + // if this is not an encoded character, return null + if ( first.charValue() != '\"' ) { + input.reset(); + return null; + } - Character second = input.next(); - return second; - } + Character second = input.next(); + return second; + } } \ No newline at end of file diff --git a/src/main/java/org/owasp/esapi/codecs/WindowsCodec.java b/src/main/java/org/owasp/esapi/codecs/WindowsCodec.java index be22640ad..fbb19a784 100644 --- a/src/main/java/org/owasp/esapi/codecs/WindowsCodec.java +++ b/src/main/java/org/owasp/esapi/codecs/WindowsCodec.java @@ -26,57 +26,57 @@ */ public class WindowsCodec extends AbstractCharacterCodec { - - /** - * {@inheritDoc} - * - * Returns Windows shell encoded character (which is ^) + + /** + * {@inheritDoc} + * + * Returns Windows shell encoded character (which is ^) * * @param immune */ - public String encodeCharacter( char[] immune, Character c ) { - char ch = c.charValue(); - - // check for immune characters - if ( containsCharacter( ch, immune ) ) { - return ""+ch; - } - - // check for alphanumeric characters - String hex = super.getHexForNonAlphanumeric( ch ); - if ( hex == null ) { - return ""+ch; - } - + public String encodeCharacter( char[] immune, Character c ) { + char ch = c.charValue(); + + // check for immune characters + if ( containsCharacter( ch, immune ) ) { + return ""+ch; + } + + // check for alphanumeric characters + String hex = super.getHexForNonAlphanumeric( ch ); + if ( hex == null ) { + return ""+ch; + } + return "^" + c; - } - + } + - /** - * {@inheritDoc} - * - * Returns the decoded version of the character starting at index, or - * null if no decoding is possible. - *

    - * Formats all are legal both upper/lower case: - * ^x - all special characters - */ - public Character decodeCharacter( PushbackSequence input ) { - input.mark(); - Character first = input.next(); - if ( first == null ) { - input.reset(); - return null; - } - - // if this is not an encoded character, return null - if ( first.charValue() != '^' ) { - input.reset(); - return null; - } + /** + * {@inheritDoc} + * + * Returns the decoded version of the character starting at index, or + * null if no decoding is possible. + *

    + * Formats all are legal both upper/lower case: + * ^x - all special characters + */ + public Character decodeCharacter( PushbackSequence input ) { + input.mark(); + Character first = input.next(); + if ( first == null ) { + input.reset(); + return null; + } + + // if this is not an encoded character, return null + if ( first.charValue() != '^' ) { + input.reset(); + return null; + } - Character second = input.next(); - return second; - } + Character second = input.next(); + return second; + } } \ No newline at end of file diff --git a/src/main/java/org/owasp/esapi/codecs/XMLEntityCodec.java b/src/main/java/org/owasp/esapi/codecs/XMLEntityCodec.java index 418f4c5a7..3ead807e3 100644 --- a/src/main/java/org/owasp/esapi/codecs/XMLEntityCodec.java +++ b/src/main/java/org/owasp/esapi/codecs/XMLEntityCodec.java @@ -23,11 +23,11 @@ * This differes from HTML entity encoding in that only the following * named entities are predefined: *

      - *
    • lt
    • - *
    • gt
    • - *
    • amp
    • - *
    • apos
    • - *
    • quot
    • + *
    • lt
    • + *
    • gt
    • + *
    • amp
    • + *
    • apos
    • + *
    • quot
    • *
    * However, the XML Specification 1.0 states in section 4.6 "Predefined * Entities" that these should still be declared for interoperability @@ -43,256 +43,256 @@ */ public class XMLEntityCodec extends AbstractCharacterCodec { - private static final String ALPHA_NUMERIC_STR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - private static final String UNENCODED_STR = ALPHA_NUMERIC_STR + " \t"; - private static final Set UNENCODED_SET = CollectionsUtil.strToUnmodifiableSet(UNENCODED_STR); - private static final HashTrie entityToCharacterMap; + private static final String ALPHA_NUMERIC_STR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + private static final String UNENCODED_STR = ALPHA_NUMERIC_STR + " \t"; + private static final Set UNENCODED_SET = CollectionsUtil.strToUnmodifiableSet(UNENCODED_STR); + private static final HashTrie entityToCharacterMap; - static - { // populate entitites - entityToCharacterMap = new HashTrie(); - entityToCharacterMap.put("lt", '<'); - entityToCharacterMap.put("gt", '>'); - entityToCharacterMap.put("amp", '&'); - entityToCharacterMap.put("apos", '\''); - entityToCharacterMap.put("quot", '"'); - } + static + { // populate entitites + entityToCharacterMap = new HashTrie(); + entityToCharacterMap.put("lt", '<'); + entityToCharacterMap.put("gt", '>'); + entityToCharacterMap.put("amp", '&'); + entityToCharacterMap.put("apos", '\''); + entityToCharacterMap.put("quot", '"'); + } - /** - * {@inheritDoc} - * - * Encodes a Character using XML entities as necessary. - * - * @param immune characters that should not be encoded as entities - */ - public String encodeCharacter(char[] immune, Character c) - { - // check for immune characters - if(containsCharacter(c, immune)) - return c.toString(); + /** + * {@inheritDoc} + * + * Encodes a Character using XML entities as necessary. + * + * @param immune characters that should not be encoded as entities + */ + public String encodeCharacter(char[] immune, Character c) + { + // check for immune characters + if(containsCharacter(c, immune)) + return c.toString(); - // check for unencoded characters - if(UNENCODED_SET.contains(c)) - return c.toString(); + // check for unencoded characters + if(UNENCODED_SET.contains(c)) + return c.toString(); - return "&#x" + Integer.toHexString(c.charValue()) + ";"; - } + return "&#x" + Integer.toHexString(c.charValue()) + ";"; + } - /** - * {@inheritDoc} - * - * Returns the decoded version of the character starting at index, or - * null if no decoding is possible. - * - * Legal formats: - *
      - *
    • &#dddd;
    • - *
    • &#xhhhh;
    • - *
    • &name;
    • - *
    - */ - public Character decodeCharacter(PushbackSequence input) - { - Character ret = null; - Character first; - Character second; + /** + * {@inheritDoc} + * + * Returns the decoded version of the character starting at index, or + * null if no decoding is possible. + * + * Legal formats: + *
      + *
    • &#dddd;
    • + *
    • &#xhhhh;
    • + *
    • &name;
    • + *
    + */ + public Character decodeCharacter(PushbackSequence input) + { + Character ret = null; + Character first; + Character second; - input.mark(); - try - { - first = input.next(); - if(first == null) - return null; + input.mark(); + try + { + first = input.next(); + if(first == null) + return null; - // if this is not an encoded character, return null - if(first != '&') - return null; + // if this is not an encoded character, return null + if(first != '&') + return null; - // test for numeric encodings - second = input.next(); - if(second==null) - return null; + // test for numeric encodings + second = input.next(); + if(second==null) + return null; - if(second=='#') - { // handle numbers - ret = getNumericEntity(input); - } - else if(Character.isLetter(second.charValue())) - { // handle entities - input.pushback(second); - ret = getNamedEntity(input); - } - } - finally - { - if(ret == null) - input.reset(); - } - return ret; - } + if(second=='#') + { // handle numbers + ret = getNumericEntity(input); + } + else if(Character.isLetter(second.charValue())) + { // handle entities + input.pushback(second); + ret = getNamedEntity(input); + } + } + finally + { + if(ret == null) + input.reset(); + } + return ret; + } - /** - * Converts the rest of a numeric entity to a character. - * @param input The input to read from. It is assumed that input - * is positioned at the character after the &# - * @return The character decoded or null on failure. - */ - private static Character getNumericEntity(PushbackSequence input) - { - Character first = input.peek(); + /** + * Converts the rest of a numeric entity to a character. + * @param input The input to read from. It is assumed that input + * is positioned at the character after the &# + * @return The character decoded or null on failure. + */ + private static Character getNumericEntity(PushbackSequence input) + { + Character first = input.peek(); - if(first == null) - return null; + if(first == null) + return null; - if(first=='x'||first=='X') - { - input.next(); // nuke X - return parseHex(input); - } - return parseNumber(input); - } + if(first=='x'||first=='X') + { + input.next(); // nuke X + return parseHex(input); + } + return parseNumber(input); + } - /** - * Convert a integer code point to a Character. - * @param i the integer - * @return i as a Character or null if i is a invalid code point - * or outside of the Java char range. - */ - private static Character int2char(int i) - { - if(!Character.isValidCodePoint(i)) - return null; - if(!(Character.MIN_VALUE <= i && i <= Character.MAX_VALUE)) - return null; // we can't 0x010000-0x100000 currently - return (char)i; - } + /** + * Convert a integer code point to a Character. + * @param i the integer + * @return i as a Character or null if i is a invalid code point + * or outside of the Java char range. + */ + private static Character int2char(int i) + { + if(!Character.isValidCodePoint(i)) + return null; + if(!(Character.MIN_VALUE <= i && i <= Character.MAX_VALUE)) + return null; // we can't 0x010000-0x100000 currently + return (char)i; + } - /** - * Converts the rest of a decimal numeric entity to a character. - * @param input The input to read from. It is assumed that input - * is positioned at the character after the &# and that - * the next char is not a 'x' or 'X'. - * @return The character decoded or null on failutre. - */ - private static Character parseNumber(PushbackSequence input) - { - StringBuilder sb = new StringBuilder(); - Character c; - while((c=input.next())!=null) - { - // end of entity? - if(c==';') - break; + /** + * Converts the rest of a decimal numeric entity to a character. + * @param input The input to read from. It is assumed that input + * is positioned at the character after the &# and that + * the next char is not a 'x' or 'X'. + * @return The character decoded or null on failutre. + */ + private static Character parseNumber(PushbackSequence input) + { + StringBuilder sb = new StringBuilder(); + Character c; + while((c=input.next())!=null) + { + // end of entity? + if(c==';') + break; - // check for digit - if(!Character.isDigit(c.charValue())) - return null; - sb.append(c); - } - if(c==null) - return null; // not ';' termintated - if(sb.length()<=0) // no digits - return null; - try - { - return int2char(Integer.parseInt(sb.toString())); - } - catch(NumberFormatException e) - { - return null; - } - } + // check for digit + if(!Character.isDigit(c.charValue())) + return null; + sb.append(c); + } + if(c==null) + return null; // not ';' termintated + if(sb.length()<=0) // no digits + return null; + try + { + return int2char(Integer.parseInt(sb.toString())); + } + catch(NumberFormatException e) + { + return null; + } + } - /** - * Converts the rest of a hexidecimal numeric entity to a character. - * @param input The input to read from. It is assumed that input - * is positioned at the character after the &#[xX] - * @return The character decoded or null on failutre. - */ - private static Character parseHex(PushbackSequence input) - { - Character c; - StringBuilder sb = new StringBuilder(); - input_loop: while((c=input.next())!=null) - { - switch(c.charValue()) - { - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - sb.append(c); - break; - case ';': - break input_loop; - default: - return null; - } - } - if(c==null) - return null; // not ';' termintated - if(sb.length()<=0) // no digits - return null; - try - { - return int2char(Integer.parseInt(sb.toString(),16)); - } - catch(NumberFormatException e) - { - return null; - } - } + /** + * Converts the rest of a hexidecimal numeric entity to a character. + * @param input The input to read from. It is assumed that input + * is positioned at the character after the &#[xX] + * @return The character decoded or null on failutre. + */ + private static Character parseHex(PushbackSequence input) + { + Character c; + StringBuilder sb = new StringBuilder(); + input_loop: while((c=input.next())!=null) + { + switch(c.charValue()) + { + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + sb.append(c); + break; + case ';': + break input_loop; + default: + return null; + } + } + if(c==null) + return null; // not ';' termintated + if(sb.length()<=0) // no digits + return null; + try + { + return int2char(Integer.parseInt(sb.toString(),16)); + } + catch(NumberFormatException e) + { + return null; + } + } - /** - * - * Converts the rest of a named entity to a character. - * null if no decoding is possible. - * @param input The input to read from. It is assumed that input - * is positioned at the character after the &. - * @return The character decoded or null on failutre. - */ - private Character getNamedEntity(PushbackSequence input) - { - StringBuilder possible = new StringBuilder(); - Map.Entry entry; - int len; + /** + * + * Converts the rest of a named entity to a character. + * null if no decoding is possible. + * @param input The input to read from. It is assumed that input + * is positioned at the character after the &. + * @return The character decoded or null on failutre. + */ + private Character getNamedEntity(PushbackSequence input) + { + StringBuilder possible = new StringBuilder(); + Map.Entry entry; + int len; - // kludge around PushbackString.... - len = Math.min(input.remainder().length(), entityToCharacterMap.getMaxKeyLength()+1); - for(int i=0;i replacedContentList = new ArrayList<>(); + /** + * The ordered-list of elements that were replaced in the last call to + * {@link #captureAndReplaceMatches(String)}, and that will be used to replace + * the {@link #replacementMarker} on the next call to + * {@link #restoreOriginalContent(String)} + */ + private final List replacedContentList = new ArrayList<>(); - /** - * Constructor. - * - * @param pattern Pattern identifying content being replaced. - */ - public EncodingPatternPreservation(Pattern pattern) { - noEncodeContent = pattern; - } + /** + * Constructor. + * + * @param pattern Pattern identifying content being replaced. + */ + public EncodingPatternPreservation(Pattern pattern) { + noEncodeContent = pattern; + } - /** - * Replaces each matching instance of this instance's Pattern with an - * identifiable replacement marker.
    - * - *
    - * After the encoding process is complete, use - * {@link #restoreOriginalContent(String)} to re-insert the original data. - * - * @param input String to adjust - * @return The adjusted String - */ - public String captureAndReplaceMatches(String input) { - if (!replacedContentList.isEmpty()) { - // This may seem odd, but this will prevent programmer error that would result - // in being unable to restore a previously tokenized String. - String message = "Previously captured state is still present in instance. Call PatternContentPreservation.reset() to clear out preserved state and to reuse the reference."; - throw new IllegalStateException(message); - } - String inputCpy = input; - Matcher matcher = noEncodeContent.matcher(input); + /** + * Replaces each matching instance of this instance's Pattern with an + * identifiable replacement marker.
    + * + *
    + * After the encoding process is complete, use + * {@link #restoreOriginalContent(String)} to re-insert the original data. + * + * @param input String to adjust + * @return The adjusted String + */ + public String captureAndReplaceMatches(String input) { + if (!replacedContentList.isEmpty()) { + // This may seem odd, but this will prevent programmer error that would result + // in being unable to restore a previously tokenized String. + String message = "Previously captured state is still present in instance. Call PatternContentPreservation.reset() to clear out preserved state and to reuse the reference."; + throw new IllegalStateException(message); + } + String inputCpy = input; + Matcher matcher = noEncodeContent.matcher(input); - while (matcher.find()) { - String replaceContent = matcher.group(0); - if (replaceContent != null) { - replacedContentList.add(replaceContent); - inputCpy = inputCpy.replaceFirst(noEncodeContent.pattern(), replacementMarker); - } - } + while (matcher.find()) { + String replaceContent = matcher.group(0); + if (replaceContent != null) { + replacedContentList.add(replaceContent); + inputCpy = inputCpy.replaceFirst(noEncodeContent.pattern(), replacementMarker); + } + } - return inputCpy; - } + return inputCpy; + } - /** - * Replaces each instance of the {@link #replacementMarker} with the original - * content, as captured by {@link #captureAndReplaceMatches(String)} - * - * @param input String to restore. - * @return String reference with all values replaced. - */ - public String restoreOriginalContent(String input) { - String result = input; - while (replacedContentList.size() > 0) { - String origValue = replacedContentList.remove(0); - result = result.replaceFirst(replacementMarker, origValue); - } + /** + * Replaces each instance of the {@link #replacementMarker} with the original + * content, as captured by {@link #captureAndReplaceMatches(String)} + * + * @param input String to restore. + * @return String reference with all values replaced. + */ + public String restoreOriginalContent(String input) { + String result = input; + while (replacedContentList.size() > 0) { + String origValue = replacedContentList.remove(0); + result = result.replaceFirst(replacementMarker, origValue); + } - return result; + return result; - } + } - /** - * Allows the marker used as a replacement to be altered. - * - * @param marker String replacment to use for regex matches. - */ - public void setReplacementMarker(String marker) { - if (!replacedContentList.isEmpty()) { - // This may seem odd, but this will prevent programmer error that would result - // in being unable to restore a previously tokenized String. - String message = "Previously captured state is still present in instance. Call PatternContentPreservation.reset() to clear out preserved state and to alter the marker."; - throw new IllegalStateException(message); - } - this.replacementMarker = marker; - } + /** + * Allows the marker used as a replacement to be altered. + * + * @param marker String replacment to use for regex matches. + */ + public void setReplacementMarker(String marker) { + if (!replacedContentList.isEmpty()) { + // This may seem odd, but this will prevent programmer error that would result + // in being unable to restore a previously tokenized String. + String message = "Previously captured state is still present in instance. Call PatternContentPreservation.reset() to clear out preserved state and to alter the marker."; + throw new IllegalStateException(message); + } + this.replacementMarker = marker; + } - /** - * Clears any stored replacement values out of the instance. - */ - public void reset() { - replacedContentList.clear(); - } + /** + * Clears any stored replacement values out of the instance. + */ + public void reset() { + replacedContentList.clear(); + } } diff --git a/src/main/java/org/owasp/esapi/configuration/XmlEsapiPropertyLoader.java b/src/main/java/org/owasp/esapi/configuration/XmlEsapiPropertyLoader.java index a801397db..45ef77f9c 100644 --- a/src/main/java/org/owasp/esapi/configuration/XmlEsapiPropertyLoader.java +++ b/src/main/java/org/owasp/esapi/configuration/XmlEsapiPropertyLoader.java @@ -133,9 +133,9 @@ protected void loadPropertiesFromFile(File file) throws ConfigurationException { private void validateAgainstXSD(InputStream xml) throws IOException, SAXException { try ( InputStream xsd = getClass().getResourceAsStream("/ESAPI-properties.xsd"); ) { SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); - Schema schema = factory.newSchema(new StreamSource(xsd)); - Validator validator = schema.newValidator(); - validator.validate(new StreamSource(xml)); + Schema schema = factory.newSchema(new StreamSource(xsd)); + Validator validator = schema.newValidator(); + validator.validate(new StreamSource(xml)); } } diff --git a/src/main/java/org/owasp/esapi/crypto/CipherSpec.java b/src/main/java/org/owasp/esapi/crypto/CipherSpec.java index d0c291749..7a8e530e8 100644 --- a/src/main/java/org/owasp/esapi/crypto/CipherSpec.java +++ b/src/main/java/org/owasp/esapi/crypto/CipherSpec.java @@ -39,306 +39,306 @@ */ public final class CipherSpec implements Serializable { - private static final long serialVersionUID = 20090822; // version, in YYYYMMDD format - - private String cipher_xform_ = ESAPI.securityConfiguration().getCipherTransformation(); - private int keySize_ = ESAPI.securityConfiguration().getEncryptionKeyLength(); // In bits - private int blockSize_ = 16; // In bytes! I.e., 128 bits!!! - private byte[] iv_ = null; + private static final long serialVersionUID = 20090822; // version, in YYYYMMDD format + + private String cipher_xform_ = ESAPI.securityConfiguration().getCipherTransformation(); + private int keySize_ = ESAPI.securityConfiguration().getEncryptionKeyLength(); // In bits + private int blockSize_ = 16; // In bytes! I.e., 128 bits!!! + private byte[] iv_ = null; - private boolean blockSizeExplicitlySet = false; // Used for check in setIV(). - - // Cipher transformation component. Format is ALG/MODE/PADDING + private boolean blockSizeExplicitlySet = false; // Used for check in setIV(). + + // Cipher transformation component. Format is ALG/MODE/PADDING private enum CipherTransformationComponent { ALG, MODE, PADDING } - /** - * CTOR that explicitly sets everything. - * @param cipherXform The cipher transformation - * @param keySize The key size (in bits). - * @param blockSize The block size (in bytes). - * @param iv The initialization vector. Null if not applicable. - */ - public CipherSpec(String cipherXform, int keySize, int blockSize, final byte[] iv) { - setCipherTransformation(cipherXform); - setKeySize(keySize); - setBlockSize(blockSize); - setIV(iv); - } - - /** - * CTOR that sets everything but IV. - * @param cipherXform The cipher transformation - * @param keySize The key size (in bits). - * @param blockSize The block size (in bytes). - */ - public CipherSpec(String cipherXform, int keySize, int blockSize) { - // Note: Do NOT use - // this(cipherXform, keySize, blockSize, null); - // because of checks in setIV(). - // - setCipherTransformation(cipherXform); - setKeySize(keySize); - setBlockSize(blockSize); - } - - /** CTOR that sets everything but block size and IV. */ - public CipherSpec(String cipherXform, int keySize) { - setCipherTransformation(cipherXform); - setKeySize(keySize); - } - - /** CTOR that sets everything except block size. */ - public CipherSpec(String cipherXform, int keySize, final byte[] iv) { - setCipherTransformation(cipherXform); - setKeySize(keySize); - setIV(iv); - } + /** + * CTOR that explicitly sets everything. + * @param cipherXform The cipher transformation + * @param keySize The key size (in bits). + * @param blockSize The block size (in bytes). + * @param iv The initialization vector. Null if not applicable. + */ + public CipherSpec(String cipherXform, int keySize, int blockSize, final byte[] iv) { + setCipherTransformation(cipherXform); + setKeySize(keySize); + setBlockSize(blockSize); + setIV(iv); + } + + /** + * CTOR that sets everything but IV. + * @param cipherXform The cipher transformation + * @param keySize The key size (in bits). + * @param blockSize The block size (in bytes). + */ + public CipherSpec(String cipherXform, int keySize, int blockSize) { + // Note: Do NOT use + // this(cipherXform, keySize, blockSize, null); + // because of checks in setIV(). + // + setCipherTransformation(cipherXform); + setKeySize(keySize); + setBlockSize(blockSize); + } + + /** CTOR that sets everything but block size and IV. */ + public CipherSpec(String cipherXform, int keySize) { + setCipherTransformation(cipherXform); + setKeySize(keySize); + } + + /** CTOR that sets everything except block size. */ + public CipherSpec(String cipherXform, int keySize, final byte[] iv) { + setCipherTransformation(cipherXform); + setKeySize(keySize); + setIV(iv); + } - /** CTOR that sets everything except for the cipher key size and possibly - * the IV. (IV may not be applicable--e.g., with ECB--or may not have - * been specified yet. - */ - public CipherSpec(final Cipher cipher) { - setCipherTransformation(cipher.getAlgorithm(), true); - setBlockSize(cipher.getBlockSize()); - if ( cipher.getIV() != null ) { - setIV(cipher.getIV()); - } - } - - /** CTOR that sets everything. */ - public CipherSpec(final Cipher cipher, int keySize) { - this(cipher); - setKeySize(keySize); - } - - /* CTOR that sets only the IV and uses defaults for everything else. */ - public CipherSpec(final byte[] iv) { - setIV(iv); - } - - /** - * Default CTOR. Creates a cipher specification for 128-bit cipher - * transformation of "AES/CBC/PKCS5Padding" and a {@code null} IV. - */ - public CipherSpec() { - // All defaults - } + /** CTOR that sets everything except for the cipher key size and possibly + * the IV. (IV may not be applicable--e.g., with ECB--or may not have + * been specified yet. + */ + public CipherSpec(final Cipher cipher) { + setCipherTransformation(cipher.getAlgorithm(), true); + setBlockSize(cipher.getBlockSize()); + if ( cipher.getIV() != null ) { + setIV(cipher.getIV()); + } + } + + /** CTOR that sets everything. */ + public CipherSpec(final Cipher cipher, int keySize) { + this(cipher); + setKeySize(keySize); + } + + /* CTOR that sets only the IV and uses defaults for everything else. */ + public CipherSpec(final byte[] iv) { + setIV(iv); + } + + /** + * Default CTOR. Creates a cipher specification for 128-bit cipher + * transformation of "AES/CBC/PKCS5Padding" and a {@code null} IV. + */ + public CipherSpec() { + // All defaults + } - /** - * Set the cipher transformation for this {@code CipherSpec}. - * @param cipherXform The cipher transformation string; e.g., "DESede/CBC/PKCS5Padding". - * @return This current {@code CipherSpec} object. - */ - public CipherSpec setCipherTransformation(String cipherXform) { - setCipherTransformation(cipherXform, false); - return this; - } + /** + * Set the cipher transformation for this {@code CipherSpec}. + * @param cipherXform The cipher transformation string; e.g., "DESede/CBC/PKCS5Padding". + * @return This current {@code CipherSpec} object. + */ + public CipherSpec setCipherTransformation(String cipherXform) { + setCipherTransformation(cipherXform, false); + return this; + } - /** - * Set the cipher transformation for this {@code CipherSpec}. This is only - * used by the CTOR {@code CipherSpec(Cipher)} and {@code CipherSpec(Cipher, int)}. - * @param cipherXform The cipher transformation string; e.g., - * "DESede/CBC/PKCS5Padding". May not be null or empty. - * @param fromCipher If true, the cipher transformation was set via - * {@code Cipher.getAlgorithm()} which may only return the - * actual algorithm. In that case we check and if all 3 parts - * were not specified, then we specify the parts that were - * based on "ECB" as the default cipher mode and "NoPadding" - * as the default padding scheme. - * @return This current {@code CipherSpec} object. - */ - private CipherSpec setCipherTransformation(String cipherXform, boolean fromCipher) { - if ( ! StringUtilities.notNullOrEmpty(cipherXform, true) ) { // Yes, really want '!' here. - throw new IllegalArgumentException("Cipher transformation may not be null or empty string (after trimming whitespace)."); - } - int parts = cipherXform.split("/").length; + /** + * Set the cipher transformation for this {@code CipherSpec}. This is only + * used by the CTOR {@code CipherSpec(Cipher)} and {@code CipherSpec(Cipher, int)}. + * @param cipherXform The cipher transformation string; e.g., + * "DESede/CBC/PKCS5Padding". May not be null or empty. + * @param fromCipher If true, the cipher transformation was set via + * {@code Cipher.getAlgorithm()} which may only return the + * actual algorithm. In that case we check and if all 3 parts + * were not specified, then we specify the parts that were + * based on "ECB" as the default cipher mode and "NoPadding" + * as the default padding scheme. + * @return This current {@code CipherSpec} object. + */ + private CipherSpec setCipherTransformation(String cipherXform, boolean fromCipher) { + if ( ! StringUtilities.notNullOrEmpty(cipherXform, true) ) { // Yes, really want '!' here. + throw new IllegalArgumentException("Cipher transformation may not be null or empty string (after trimming whitespace)."); + } + int parts = cipherXform.split("/").length; // Assertion should be okay here as these conditions are checked // elsewhere and this method is private. - assert ( !fromCipher ? (parts == 3) : true ) : - "Malformed cipherXform (" + cipherXform + "); must have form: \"alg/mode/paddingscheme\""; - if ( fromCipher && (parts != 3) ) { - // Indicates cipherXform was set based on Cipher.getAlgorithm() - // and thus may not be a *complete* cipher transformation. - if ( parts == 1 ) { - // Only algorithm was given. - cipherXform += "/ECB/NoPadding"; - } else if ( parts == 2 ) { - // Only algorithm and mode was given. - cipherXform += "/NoPadding"; - } else if ( parts == 3 ) { + assert ( !fromCipher ? (parts == 3) : true ) : + "Malformed cipherXform (" + cipherXform + "); must have form: \"alg/mode/paddingscheme\""; + if ( fromCipher && (parts != 3) ) { + // Indicates cipherXform was set based on Cipher.getAlgorithm() + // and thus may not be a *complete* cipher transformation. + if ( parts == 1 ) { + // Only algorithm was given. + cipherXform += "/ECB/NoPadding"; + } else if ( parts == 2 ) { + // Only algorithm and mode was given. + cipherXform += "/NoPadding"; + } else if ( parts == 3 ) { // All three parts provided. Do nothing. Could happen if not compiled with // assertions enabled, but there are explicit checks elsewhere. - ; // Do nothing - shown only for completeness. - } else { - // Should never happen unless Cipher implementation is totally screwed up. - throw new IllegalArgumentException("Cipher transformation '" + - cipherXform + "' must have form \"alg/mode/paddingscheme\""); - } - } else if ( !fromCipher && parts != 3 ) { - throw new IllegalArgumentException("Malformed cipherXform (" + cipherXform + - "); must have form: \"alg/mode/paddingscheme\""); - } + ; // Do nothing - shown only for completeness. + } else { + // Should never happen unless Cipher implementation is totally screwed up. + throw new IllegalArgumentException("Cipher transformation '" + + cipherXform + "' must have form \"alg/mode/paddingscheme\""); + } + } else if ( !fromCipher && parts != 3 ) { + throw new IllegalArgumentException("Malformed cipherXform (" + cipherXform + + "); must have form: \"alg/mode/paddingscheme\""); + } // Assertion should also be okay here as these conditions are checked // elsewhere and this method is private. - assert cipherXform.split("/").length == 3 : "Implementation error setCipherTransformation()"; - this.cipher_xform_ = cipherXform; - return this; - } - - /** - * Get the cipher transformation. - * @return The cipher transformation {@code String}. - */ - public String getCipherTransformation() { - return cipher_xform_; - } + assert cipherXform.split("/").length == 3 : "Implementation error setCipherTransformation()"; + this.cipher_xform_ = cipherXform; + return this; + } + + /** + * Get the cipher transformation. + * @return The cipher transformation {@code String}. + */ + public String getCipherTransformation() { + return cipher_xform_; + } - /** - * Set the key size for this {@code CipherSpec}. - * @param keySize The key size, in bits. Must be positive integer. - * @return This current {@code CipherSpec} object. - */ - public CipherSpec setKeySize(int keySize) { - if ( keySize <= 0 ) { - throw new IllegalArgumentException("keySize must be > 0; keySize=" + keySize); - } - this.keySize_ = keySize; - return this; - } + /** + * Set the key size for this {@code CipherSpec}. + * @param keySize The key size, in bits. Must be positive integer. + * @return This current {@code CipherSpec} object. + */ + public CipherSpec setKeySize(int keySize) { + if ( keySize <= 0 ) { + throw new IllegalArgumentException("keySize must be > 0; keySize=" + keySize); + } + this.keySize_ = keySize; + return this; + } - /** - * Retrieve the key size, in bits. - * @return The key size, in bits, is returned. - */ - public int getKeySize() { - return keySize_; - } + /** + * Retrieve the key size, in bits. + * @return The key size, in bits, is returned. + */ + public int getKeySize() { + return keySize_; + } - /** - * Set the block size for this {@code CipherSpec}. - * @param blockSize The block size, in bytes. Must be positive integer appropriate - * for the specified cipher algorithm. - * @return This current {@code CipherSpec} object. - */ - public CipherSpec setBlockSize(int blockSize) { - if ( blockSize <= 0 ) { - throw new IllegalArgumentException("blockSize must be > 0; blockSize=" + blockSize); - } - this.blockSize_ = blockSize; - blockSizeExplicitlySet = true; - return this; - } + /** + * Set the block size for this {@code CipherSpec}. + * @param blockSize The block size, in bytes. Must be positive integer appropriate + * for the specified cipher algorithm. + * @return This current {@code CipherSpec} object. + */ + public CipherSpec setBlockSize(int blockSize) { + if ( blockSize <= 0 ) { + throw new IllegalArgumentException("blockSize must be > 0; blockSize=" + blockSize); + } + this.blockSize_ = blockSize; + blockSizeExplicitlySet = true; + return this; + } - /** - * Retrieve the block size, in bytes. - * @return The block size, in bytes, is returned. - */ - public int getBlockSize() { - return blockSize_; - } + /** + * Retrieve the block size, in bytes. + * @return The block size, in bytes, is returned. + */ + public int getBlockSize() { + return blockSize_; + } - /** - * Retrieve the cipher algorithm. - * @return The cipher algorithm. - */ - public String getCipherAlgorithm() { - return getFromCipherXform(CipherTransformationComponent.ALG); - } - - /** - * Retrieve the cipher mode. - * @return The cipher mode. - */ - public String getCipherMode() { - return getFromCipherXform(CipherTransformationComponent.MODE); - } - - /** - * Retrieve the cipher padding scheme. - * @return The padding scheme is returned. - */ - public String getPaddingScheme() { - return getFromCipherXform(CipherTransformationComponent.PADDING); - } - - /** - * Retrieve the initialization vector (IV). - * @return The IV as a byte array. - */ - public byte[] getIV() { - return iv_; - } - - /** - * Set the initialization vector (IV). - * @param iv The byte array to set as the IV. A copy of the IV is saved. - * This parameter is ignored if the cipher mode does not - * require an IV. - * @return This current {@code CipherSpec} object. - */ - public CipherSpec setIV(final byte[] iv) { - if ( ! ( requiresIV() && (iv != null && iv.length != 0) ) ) { - throw new IllegalArgumentException("Required IV cannot be null or 0 length."); - } - - // Don't store a reference, but make a copy! When an IV is provided, it generally should - // be the same length as the block size of the cipher. - if ( iv != null ) { // Allow null IV for ECB mode. - // TODO: FIXME: As per email from Jeff Walton to Kevin Wall dated 12/03/2013, - // this is not always true. E.g., for CCM, the IV length is supposed - // to be 7, 8, 9, 10, 11, 12, or 13 octets because of - // it's formatting function. + /** + * Retrieve the cipher algorithm. + * @return The cipher algorithm. + */ + public String getCipherAlgorithm() { + return getFromCipherXform(CipherTransformationComponent.ALG); + } + + /** + * Retrieve the cipher mode. + * @return The cipher mode. + */ + public String getCipherMode() { + return getFromCipherXform(CipherTransformationComponent.MODE); + } + + /** + * Retrieve the cipher padding scheme. + * @return The padding scheme is returned. + */ + public String getPaddingScheme() { + return getFromCipherXform(CipherTransformationComponent.PADDING); + } + + /** + * Retrieve the initialization vector (IV). + * @return The IV as a byte array. + */ + public byte[] getIV() { + return iv_; + } + + /** + * Set the initialization vector (IV). + * @param iv The byte array to set as the IV. A copy of the IV is saved. + * This parameter is ignored if the cipher mode does not + * require an IV. + * @return This current {@code CipherSpec} object. + */ + public CipherSpec setIV(final byte[] iv) { + if ( ! ( requiresIV() && (iv != null && iv.length != 0) ) ) { + throw new IllegalArgumentException("Required IV cannot be null or 0 length."); + } + + // Don't store a reference, but make a copy! When an IV is provided, it generally should + // be the same length as the block size of the cipher. + if ( iv != null ) { // Allow null IV for ECB mode. + // TODO: FIXME: As per email from Jeff Walton to Kevin Wall dated 12/03/2013, + // this is not always true. E.g., for CCM, the IV length is supposed + // to be 7, 8, 9, 10, 11, 12, or 13 octets because of + // it's formatting function. /*** - if ( iv.length != this.getBlockSize() && blockSizeExplicitlySet ) { - throw new IllegalArgumentException("IV must be same length as cipher block size (" + - this.getBlockSize() + " bytes)"); - } + if ( iv.length != this.getBlockSize() && blockSizeExplicitlySet ) { + throw new IllegalArgumentException("IV must be same length as cipher block size (" + + this.getBlockSize() + " bytes)"); + } ***/ - iv_ = new byte[ iv.length ]; - CryptoHelper.copyByteArray(iv, iv_); - } - return this; - } + iv_ = new byte[ iv.length ]; + CryptoHelper.copyByteArray(iv, iv_); + } + return this; + } - /** - * Return true if the cipher mode requires an IV. - * @return True if the cipher mode requires an IV, otherwise false. - * */ - public boolean requiresIV() { - - String cm = getCipherMode(); - - // Add any other cipher modes supported by JCE but not requiring IV. - // ECB is the only one I'm aware of that doesn't. Mode is not case - // sensitive. - if ( "ECB".equalsIgnoreCase(cm) ) { - return false; - } - return true; - } - - /** - * Override {@code Object.toString()} to provide something more useful. - * @return A meaningful string describing this object. - */ - @Override - public String toString() { - StringBuilder sb = new StringBuilder("CipherSpec: "); - sb.append( getCipherTransformation() ).append("; keysize= ").append( getKeySize() ); - sb.append(" bits; blocksize= ").append( getBlockSize() ).append(" bytes"); - byte[] iv = getIV(); - String ivLen = null; - if ( iv != null ) { - ivLen = "" + iv.length; // Convert length to a string - } else { - ivLen = "[No IV present (not set or not required)]"; - } - sb.append("; IV length = ").append( ivLen ).append(" bytes."); - return sb.toString(); - } - + /** + * Return true if the cipher mode requires an IV. + * @return True if the cipher mode requires an IV, otherwise false. + * */ + public boolean requiresIV() { + + String cm = getCipherMode(); + + // Add any other cipher modes supported by JCE but not requiring IV. + // ECB is the only one I'm aware of that doesn't. Mode is not case + // sensitive. + if ( "ECB".equalsIgnoreCase(cm) ) { + return false; + } + return true; + } + + /** + * Override {@code Object.toString()} to provide something more useful. + * @return A meaningful string describing this object. + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder("CipherSpec: "); + sb.append( getCipherTransformation() ).append("; keysize= ").append( getKeySize() ); + sb.append(" bits; blocksize= ").append( getBlockSize() ).append(" bytes"); + byte[] iv = getIV(); + String ivLen = null; + if ( iv != null ) { + ivLen = "" + iv.length; // Convert length to a string + } else { + ivLen = "[No IV present (not set or not required)]"; + } + sb.append("; IV length = ").append( ivLen ).append(" bytes."); + return sb.toString(); + } + /** * {@inheritDoc} */ @@ -399,19 +399,19 @@ public int hashCode() { */ protected boolean canEqual(Object other) { return (other instanceof CipherSpec); - } - - /** - * Split the current cipher transformation and return the requested part. - * @param component The component of the cipher transformation to return. - * @return The cipher algorithm, cipher mode, or padding, as requested. - */ - private String getFromCipherXform(CipherTransformationComponent component) { + } + + /** + * Split the current cipher transformation and return the requested part. + * @param component The component of the cipher transformation to return. + * @return The cipher algorithm, cipher mode, or padding, as requested. + */ + private String getFromCipherXform(CipherTransformationComponent component) { int part = component.ordinal(); - String[] parts = getCipherTransformation().split("/"); + String[] parts = getCipherTransformation().split("/"); // Assertion should also be okay here as these conditions are checked // elsewhere and this method is private. - assert parts.length == 3 : "Invalid cipher transformation: " + getCipherTransformation(); - return parts[part]; - } + assert parts.length == 3 : "Invalid cipher transformation: " + getCipherTransformation(); + return parts[part]; + } } diff --git a/src/main/java/org/owasp/esapi/crypto/CryptoDiscoverer.java b/src/main/java/org/owasp/esapi/crypto/CryptoDiscoverer.java index e42c8cf1f..8f89c7e95 100644 --- a/src/main/java/org/owasp/esapi/crypto/CryptoDiscoverer.java +++ b/src/main/java/org/owasp/esapi/crypto/CryptoDiscoverer.java @@ -22,8 +22,8 @@ import java.util.regex.Pattern; public class CryptoDiscoverer { - private static String EOL = System.getProperty("line.separator", "\n"); - + private static String EOL = System.getProperty("line.separator", "\n"); + public static void main(String... args) { String provider = ".*"; String algorithm = ".*"; @@ -69,7 +69,7 @@ public static void main(String... args) { private static void usage() { System.out.println("CryptoDiscoverer - Discover or Query for available Crypto Providers and Algorithms"); System.out.println(EOL + "\t--help\t\t\t\t\tShows this message" + EOL + - "\t--provider \t\tSearch for particular Provider" + EOL + + "\t--provider \t\tSearch for particular Provider" + EOL + "\t--algorithm \t\tSearch for a particular Algorithm" + EOL + EOL); } } diff --git a/src/main/java/org/owasp/esapi/crypto/CryptoHelper.java b/src/main/java/org/owasp/esapi/crypto/CryptoHelper.java index 31f276ac4..805c3565c 100644 --- a/src/main/java/org/owasp/esapi/crypto/CryptoHelper.java +++ b/src/main/java/org/owasp/esapi/crypto/CryptoHelper.java @@ -36,168 +36,168 @@ * @since 2.0 */ public class CryptoHelper { - - private static final Logger logger = ESAPI.getLogger("CryptoHelper"); + + private static final Logger logger = ESAPI.getLogger("CryptoHelper"); - // TODO: Also consider supplying implementation of RFC 2898 / PKCS#5 PBKDF2 - // in this file as well??? Maybe save for ESAPI 2.1 or 3.0. - /** - * Generate a random secret key appropriate to the specified cipher algorithm - * and key size. - * @param alg The cipher algorithm or cipher transformation. (If the latter is - * passed, the cipher algorithm is determined from it.) Cannot be - * null or empty. - * @param keySize The key size, in bits. - * @return A random {@code SecretKey} is returned. - * @throws EncryptionException Thrown if cannot create secret key conforming to - * requested algorithm with requested size. Typically this is caused by - * specifying an unavailable algorithm or invalid key size. - */ - public static SecretKey generateSecretKey(String alg, int keySize) - throws EncryptionException - { - if ( alg == null || alg.equals("") ) { - throw new IllegalArgumentException("Algorithm must not be null or empty."); // Avoid later possibly ambiguous NPE. - } - if ( keySize <= 0 ) { - throw new IllegalArgumentException("Key size must be positive."); // Usually should be an even multiple of 8, but not strictly required by alg. - } - // Don't use CipherSpec here to get algorithm as this may cause assertion - // to fail (when enabled) if only algorithm name is passed to us. - String[] cipherSpec = alg.split("/"); - String cipherAlg = cipherSpec[0]; - try { - // Special case for things like PBEWithMD5AndDES or PBEWithSHA1AndDESede. - // In such cases, the key generator should only request an instance of "PBE". - if ( cipherAlg.toUpperCase().startsWith("PBEWITH") ) { - cipherAlg = "PBE"; - } - KeyGenerator kgen = - KeyGenerator.getInstance( cipherAlg ); - kgen.init(keySize); - return kgen.generateKey(); - } catch (NoSuchAlgorithmException e) { - throw new EncryptionException("Failed to generate random secret key", - "Invalid algorithm. Failed to generate secret key for " + alg + " with size of " + keySize + " bits.", e); - } catch (InvalidParameterException e) { - throw new EncryptionException("Failed to generate random secret key - invalid key size specified.", - "Invalid key size. Failed to generate secret key for " + alg + " with size of " + keySize + " bits.", e); - } - } + // TODO: Also consider supplying implementation of RFC 2898 / PKCS#5 PBKDF2 + // in this file as well??? Maybe save for ESAPI 2.1 or 3.0. + /** + * Generate a random secret key appropriate to the specified cipher algorithm + * and key size. + * @param alg The cipher algorithm or cipher transformation. (If the latter is + * passed, the cipher algorithm is determined from it.) Cannot be + * null or empty. + * @param keySize The key size, in bits. + * @return A random {@code SecretKey} is returned. + * @throws EncryptionException Thrown if cannot create secret key conforming to + * requested algorithm with requested size. Typically this is caused by + * specifying an unavailable algorithm or invalid key size. + */ + public static SecretKey generateSecretKey(String alg, int keySize) + throws EncryptionException + { + if ( alg == null || alg.equals("") ) { + throw new IllegalArgumentException("Algorithm must not be null or empty."); // Avoid later possibly ambiguous NPE. + } + if ( keySize <= 0 ) { + throw new IllegalArgumentException("Key size must be positive."); // Usually should be an even multiple of 8, but not strictly required by alg. + } + // Don't use CipherSpec here to get algorithm as this may cause assertion + // to fail (when enabled) if only algorithm name is passed to us. + String[] cipherSpec = alg.split("/"); + String cipherAlg = cipherSpec[0]; + try { + // Special case for things like PBEWithMD5AndDES or PBEWithSHA1AndDESede. + // In such cases, the key generator should only request an instance of "PBE". + if ( cipherAlg.toUpperCase().startsWith("PBEWITH") ) { + cipherAlg = "PBE"; + } + KeyGenerator kgen = + KeyGenerator.getInstance( cipherAlg ); + kgen.init(keySize); + return kgen.generateKey(); + } catch (NoSuchAlgorithmException e) { + throw new EncryptionException("Failed to generate random secret key", + "Invalid algorithm. Failed to generate secret key for " + alg + " with size of " + keySize + " bits.", e); + } catch (InvalidParameterException e) { + throw new EncryptionException("Failed to generate random secret key - invalid key size specified.", + "Invalid key size. Failed to generate secret key for " + alg + " with size of " + keySize + " bits.", e); + } + } - /** - * The method is ESAPI's Key Derivation Function (KDF) that computes a - * derived key from the {@code keyDerivationKey} for either - * encryption / decryption or for authentication. - *

    - * CAUTION: If this algorithm for computing derived keys from the - * key derivation key is ever changed, we risk breaking backward compatibility of being - * able to decrypt data previously encrypted with earlier / different versions - * of this method. Therefore, do not change this unless you are 100% certain that - * what you are doing will NOT change either of the derived keys for - * ANY "key derivation key" AT ALL!!! - *

    - * NOTE: This method is generally not intended to be called separately. - * It is used by ESAPI's reference crypto implementation class {@code JavaEncryptor} - * and might be useful for someone implementing their own replacement class, but - * generally it is not something that is useful to application client code. - * - * @param keyDerivationKey A key used as an input to a key derivation function - * to derive other keys. This is the key that generally - * is created using some key generation mechanism such as - * {@link #generateSecretKey(String, int)}. The - * "input" key from which the other keys are derived. - * The derived key will have the same algorithm type - * as this key. - * @param keySize The cipher's key size (in bits) for the {@code keyDerivationKey}. - * Must have a minimum size of 56 bits and be an integral multiple of 8-bits. - * Note: The derived key will have the same size as this. - * @param purpose The purpose for the derived key. Must be either the - * string "encryption" or "authenticity". Use "encryption" for + /** + * The method is ESAPI's Key Derivation Function (KDF) that computes a + * derived key from the {@code keyDerivationKey} for either + * encryption / decryption or for authentication. + *

    + * CAUTION: If this algorithm for computing derived keys from the + * key derivation key is ever changed, we risk breaking backward compatibility of being + * able to decrypt data previously encrypted with earlier / different versions + * of this method. Therefore, do not change this unless you are 100% certain that + * what you are doing will NOT change either of the derived keys for + * ANY "key derivation key" AT ALL!!! + *

    + * NOTE: This method is generally not intended to be called separately. + * It is used by ESAPI's reference crypto implementation class {@code JavaEncryptor} + * and might be useful for someone implementing their own replacement class, but + * generally it is not something that is useful to application client code. + * + * @param keyDerivationKey A key used as an input to a key derivation function + * to derive other keys. This is the key that generally + * is created using some key generation mechanism such as + * {@link #generateSecretKey(String, int)}. The + * "input" key from which the other keys are derived. + * The derived key will have the same algorithm type + * as this key. + * @param keySize The cipher's key size (in bits) for the {@code keyDerivationKey}. + * Must have a minimum size of 56 bits and be an integral multiple of 8-bits. + * Note: The derived key will have the same size as this. + * @param purpose The purpose for the derived key. Must be either the + * string "encryption" or "authenticity". Use "encryption" for * creating a derived key to use for confidentiality, and "authenticity" * for a derived key to use with a MAC to ensure message authenticity. - * @return The derived {@code SecretKey} to be used according - * to the specified purpose. Note that this serves the same purpose - * as "label" in section 5.1 of NIST SP 800-108. - * @throws NoSuchAlgorithmException The {@code keyDerivationKey} has an unsupported - * encryption algorithm or no current JCE provider supports - * "HmacSHA1". - * @throws EncryptionException If "UTF-8" is not supported as an encoding, then - * this is thrown with the original {@code UnsupportedEncodingException} - * as the cause. (NOTE: This should never happen as "UTF-8" is supposed to - * be a common encoding supported by all Java implementations. Support - * for it is usually in rt.jar.) This exception is also thrown if the - * requested {@code keySize} parameter exceeds the length of the number of - * bytes provded in the {@code keyDerivationKey} parameter. - * @throws InvalidKeyException Likely indicates a coding error. Should not happen. - * @throws EncryptionException Throw for some precondition violations. - * @deprecated Use same method in {@code KeyDerivationFunction} instead. This method will be removed as of - * ESAPI release 2.3 so if you are using this, please CHANGE YOUR CODE. Note that the replacement - * is not a static method, so create your own wrapper if you wish, but this will soon disappear. - */ + * @return The derived {@code SecretKey} to be used according + * to the specified purpose. Note that this serves the same purpose + * as "label" in section 5.1 of NIST SP 800-108. + * @throws NoSuchAlgorithmException The {@code keyDerivationKey} has an unsupported + * encryption algorithm or no current JCE provider supports + * "HmacSHA1". + * @throws EncryptionException If "UTF-8" is not supported as an encoding, then + * this is thrown with the original {@code UnsupportedEncodingException} + * as the cause. (NOTE: This should never happen as "UTF-8" is supposed to + * be a common encoding supported by all Java implementations. Support + * for it is usually in rt.jar.) This exception is also thrown if the + * requested {@code keySize} parameter exceeds the length of the number of + * bytes provded in the {@code keyDerivationKey} parameter. + * @throws InvalidKeyException Likely indicates a coding error. Should not happen. + * @throws EncryptionException Throw for some precondition violations. + * @deprecated Use same method in {@code KeyDerivationFunction} instead. This method will be removed as of + * ESAPI release 2.3 so if you are using this, please CHANGE YOUR CODE. Note that the replacement + * is not a static method, so create your own wrapper if you wish, but this will soon disappear. + */ @Deprecated - public static SecretKey computeDerivedKey(SecretKey keyDerivationKey, int keySize, String purpose) - throws NoSuchAlgorithmException, InvalidKeyException, EncryptionException - { + public static SecretKey computeDerivedKey(SecretKey keyDerivationKey, int keySize, String purpose) + throws NoSuchAlgorithmException, InvalidKeyException, EncryptionException + { // Fingers cross; maybe this will help. logger.warning(Logger.SECURITY_AUDIT, "Your code is using the deprecated CryptoHelper.computeDerivedKey() method which will be removed next release"); - if ( keyDerivationKey == null ) { + if ( keyDerivationKey == null ) { throw new IllegalArgumentException("Key derivation key cannot be null."); } - // We would choose a larger minimum key size, but we want to be - // able to accept DES for legacy encryption needs. - if ( keySize < 56 ) { + // We would choose a larger minimum key size, but we want to be + // able to accept DES for legacy encryption needs. + if ( keySize < 56 ) { throw new IllegalArgumentException("Key has size of " + keySize + ", which is less than minimum of 56-bits."); } - if ( (keySize % 8) != 0 ) { + if ( (keySize % 8) != 0 ) { throw new IllegalArgumentException("Key size (" + keySize + ") must be a even multiple of 8-bits."); } - if ( purpose == null ) { + if ( purpose == null ) { throw new IllegalArgumentException("'purpose' may not be null."); } - if ( ! ( purpose.equals("encryption") || purpose.equals("authenticity") ) ) { - throw new IllegalArgumentException("Purpose must be \"encryption\" or \"authenticity\"."); + if ( ! ( purpose.equals("encryption") || purpose.equals("authenticity") ) ) { + throw new IllegalArgumentException("Purpose must be \"encryption\" or \"authenticity\"."); } - // DISCUSS: Should we use HmacSHA1 (what we were using) or the HMAC defined by - // Encryptor.KDF.PRF instead? Either way, this is not compatible with - // previous ESAPI versions. JavaEncryptor doesn't use this any longer. + // DISCUSS: Should we use HmacSHA1 (what we were using) or the HMAC defined by + // Encryptor.KDF.PRF instead? Either way, this is not compatible with + // previous ESAPI versions. JavaEncryptor doesn't use this any longer. // ANSWER: This is deprecated and will be removed in 2.3.0.0, so it really matter // that much. However, Since the property Encryptor.KDF.PRF is (and has // been) "HMacSHA256". changing this could unintentionally break code. - KeyDerivationFunction kdf = new KeyDerivationFunction( - KeyDerivationFunction.PRF_ALGORITHMS.HmacSHA1); - return kdf.computeDerivedKey(keyDerivationKey, keySize, purpose); - } + KeyDerivationFunction kdf = new KeyDerivationFunction( + KeyDerivationFunction.PRF_ALGORITHMS.HmacSHA1); + return kdf.computeDerivedKey(keyDerivationKey, keySize, purpose); + } - /** - * Return true if specified cipher mode is one of those specified in the - * {@code ESAPI.properties} file that supports both confidentiality - * and authenticity (i.e., a "combined cipher mode" as NIST refers - * to it). - * @param cipherMode The specified cipher mode to be used for the encryption - * or decryption operation. - * @return true if the specified cipher mode is in the comma-separated list - * of cipher modes supporting both confidentiality and authenticity; - * otherwise false. - * @see org.owasp.esapi.SecurityConfiguration#getCombinedCipherModes() - */ - public static boolean isCombinedCipherMode(String cipherMode) - { - if ( cipherMode == null ) { + /** + * Return true if specified cipher mode is one of those specified in the + * {@code ESAPI.properties} file that supports both confidentiality + * and authenticity (i.e., a "combined cipher mode" as NIST refers + * to it). + * @param cipherMode The specified cipher mode to be used for the encryption + * or decryption operation. + * @return true if the specified cipher mode is in the comma-separated list + * of cipher modes supporting both confidentiality and authenticity; + * otherwise false. + * @see org.owasp.esapi.SecurityConfiguration#getCombinedCipherModes() + */ + public static boolean isCombinedCipherMode(String cipherMode) + { + if ( cipherMode == null ) { throw new IllegalArgumentException("Cipher mode may not be null"); } - if ( cipherMode.equals("") ) { + if ( cipherMode.equals("") ) { throw new IllegalArgumentException("Cipher mode may not be empty string"); } - List combinedCipherModes = - ESAPI.securityConfiguration().getCombinedCipherModes(); - return combinedCipherModes.contains( cipherMode ); - } + List combinedCipherModes = + ESAPI.securityConfiguration().getCombinedCipherModes(); + return combinedCipherModes.contains( cipherMode ); + } - /** + /** * Return true if specified cipher mode is one that may be used for * encryption / decryption operations via {@link org.owasp.esapi.Encryptor}. * @param cipherMode The specified cipher mode to be used for the encryption @@ -209,16 +209,16 @@ public static boolean isCombinedCipherMode(String cipherMode) * @see org.owasp.esapi.SecurityConfiguration#getCombinedCipherModes() * @see org.owasp.esapi.SecurityConfiguration#getAdditionalAllowedCipherModes() */ - public static boolean isAllowedCipherMode(String cipherMode) - { - if ( isCombinedCipherMode(cipherMode) ) { - return true; - } - List extraCipherModes = - ESAPI.securityConfiguration().getAdditionalAllowedCipherModes(); - return extraCipherModes.contains( cipherMode ); - } - + public static boolean isAllowedCipherMode(String cipherMode) + { + if ( isCombinedCipherMode(cipherMode) ) { + return true; + } + List extraCipherModes = + ESAPI.securityConfiguration().getAdditionalAllowedCipherModes(); + return extraCipherModes.contains( cipherMode ); + } + /** * Check to see if a Message Authentication Code (MAC) is required * for a given {@code CipherText} object and the current ESAPI.property @@ -247,7 +247,7 @@ public static boolean isMACRequired(CipherText ct) { // additional computing time. return ( !preferredCipherMode && wantsMAC ); } - + /** * If a Message Authentication Code (MAC) is required for the specified * {@code CipherText} object, then attempt to validate the MAC that @@ -268,7 +268,7 @@ public static boolean isCipherTextMACvalid(SecretKey sk, CipherText ct) { if ( CryptoHelper.isMACRequired( ct ) ) { try { - KeyDerivationFunction kdf = new KeyDerivationFunction( ct.getKDF_PRF() ); + KeyDerivationFunction kdf = new KeyDerivationFunction( ct.getKDF_PRF() ); SecretKey authKey = kdf.computeDerivedKey(sk, ct.getKeySize(), "authenticity"); boolean validMAC = ct.validateMAC( authKey ); return validMAC; @@ -283,34 +283,34 @@ public static boolean isCipherTextMACvalid(SecretKey sk, CipherText ct) return true; } - /** - * Overwrite a byte array with a specified byte. This is frequently done - * to a plaintext byte array so the sensitive data is not lying around - * exposed in memory. - * @param bytes The byte array to be overwritten. - * @param x The byte array {@code bytes} is overwritten with this byte. - */ - public static void overwrite(byte[] bytes, byte x) - { - Arrays.fill(bytes, x); - } - - /** - * Overwrite a byte array with the byte containing '*'. That is, call - *

    -	 * 		overwrite(bytes, (byte)'*');
    -	 * 
    - * @param bytes The byte array to be overwritten. - */ - public static void overwrite(byte[] bytes) - { - overwrite(bytes, (byte)'*'); - } - - // These provide for a bit more type safety when copying bytes around. - /** - * Same as {@code System.arraycopy(src, 0, dest, 0, length)}. - * + /** + * Overwrite a byte array with a specified byte. This is frequently done + * to a plaintext byte array so the sensitive data is not lying around + * exposed in memory. + * @param bytes The byte array to be overwritten. + * @param x The byte array {@code bytes} is overwritten with this byte. + */ + public static void overwrite(byte[] bytes, byte x) + { + Arrays.fill(bytes, x); + } + + /** + * Overwrite a byte array with the byte containing '*'. That is, call + *
    +     *         overwrite(bytes, (byte)'*');
    +     * 
    + * @param bytes The byte array to be overwritten. + */ + public static void overwrite(byte[] bytes) + { + overwrite(bytes, (byte)'*'); + } + + // These provide for a bit more type safety when copying bytes around. + /** + * Same as {@code System.arraycopy(src, 0, dest, 0, length)}. + * * @param src the source array. * @param dest the destination array. * @param length the number of array elements to be copied. @@ -318,40 +318,40 @@ public static void overwrite(byte[] bytes) * access of data outside array bounds. * @exception NullPointerException if either src or * dest is null. - */ - public static void copyByteArray(final byte[] src, byte[] dest, int length) - { - System.arraycopy(src, 0, dest, 0, length); - } - - /** - * Same as {@code copyByteArray(src, dest, src.length)}. + */ + public static void copyByteArray(final byte[] src, byte[] dest, int length) + { + System.arraycopy(src, 0, dest, 0, length); + } + + /** + * Same as {@code copyByteArray(src, dest, src.length)}. * @param src the source array. * @param dest the destination array. * @exception IndexOutOfBoundsException if copying would cause * access of data outside array bounds. * @exception NullPointerException if either src or * dest is null. - */ - public static void copyByteArray(final byte[] src, byte[] dest) - { - copyByteArray(src, dest, src.length); - } - - /** - * A "safe" array comparison that is not vulnerable to side-channel - * "timing attacks". All comparisons of non-null, equal length bytes should - * take same amount of time. We use this for cryptographic comparisons. - * - * @param b1 A byte array to compare. - * @param b2 A second byte array to compare. - * @return {@code true} if both byte arrays are null or if both byte - * arrays are identical or have the same value; otherwise - * {@code false} is returned. + */ + public static void copyByteArray(final byte[] src, byte[] dest) + { + copyByteArray(src, dest, src.length); + } + + /** + * A "safe" array comparison that is not vulnerable to side-channel + * "timing attacks". All comparisons of non-null, equal length bytes should + * take same amount of time. We use this for cryptographic comparisons. + * + * @param b1 A byte array to compare. + * @param b2 A second byte array to compare. + * @return {@code true} if both byte arrays are null or if both byte + * arrays are identical or have the same value; otherwise + * {@code false} is returned. * @deprecated Use java.security.MessageDigest#isEqual(byte[], byte[]) instead. - */ + */ @Deprecated - public static boolean arrayCompare(byte[] b1, byte[] b2) { + public static boolean arrayCompare(byte[] b1, byte[] b2) { // Note: See GitHub issue #246 and #554. // If we make Java 8 the minimal ESAPI baseline before we remove this // method, we can at least remove these next 6 lines. (Issue 554.) @@ -362,53 +362,53 @@ public static boolean arrayCompare(byte[] b1, byte[] b2) { return false; // Prevent NPE; compatibility with Java 8 and later. } return java.security.MessageDigest.isEqual(b1, b2); - } + } - /** - * Is this particular KDF version number one that is sane? For that, we - * just make sure it is inbounds of the valid range which is: - *
    -	 *     [20110203, 99991231]
    -	 * 
    - * @param kdfVers KDF version # that we are checking. Generally this is - * extracted from the serialized {@code CipherText}. - * @param restrictToCurrent If this is set, we do an additional check - * to see if the KDF version is a later version than the - * one that this current ESAPI version supports. - * @param throwIfError Instead of returning {@code false} in the case of - * an error, throw an {@code IllegalArgumentException} - * @return True if in range, false otherwise (except if {@code throwIfError} - * is true.} - */ - public static boolean isValidKDFVersion(int kdfVers, boolean restrictToCurrent, - boolean throwIfError) - throws IllegalArgumentException - { - boolean ret = true; - - if ( kdfVers < KeyDerivationFunction.originalVersion || kdfVers > 99991231 ) { - ret = false; - } else if ( restrictToCurrent ) { - ret = ( kdfVers <= KeyDerivationFunction.kdfVersion ); - } - if ( ret ) { - return ret; // True - } else { // False, so throw or not. - logger.warning(Logger.SECURITY_FAILURE, "Possible data tampering. Encountered invalid KDF version #. " + - ( throwIfError ? "Throwing IllegalArgumentException" : "" )); - if ( throwIfError ) { - throw new IllegalArgumentException("Version (" + kdfVers + ") invalid. " + - "Must be date in format of YYYYMMDD between " + KeyDerivationFunction.originalVersion + "and 99991231."); - } - } - return false; - } - + /** + * Is this particular KDF version number one that is sane? For that, we + * just make sure it is inbounds of the valid range which is: + *
    +     *     [20110203, 99991231]
    +     * 
    + * @param kdfVers KDF version # that we are checking. Generally this is + * extracted from the serialized {@code CipherText}. + * @param restrictToCurrent If this is set, we do an additional check + * to see if the KDF version is a later version than the + * one that this current ESAPI version supports. + * @param throwIfError Instead of returning {@code false} in the case of + * an error, throw an {@code IllegalArgumentException} + * @return True if in range, false otherwise (except if {@code throwIfError} + * is true.} + */ + public static boolean isValidKDFVersion(int kdfVers, boolean restrictToCurrent, + boolean throwIfError) + throws IllegalArgumentException + { + boolean ret = true; + + if ( kdfVers < KeyDerivationFunction.originalVersion || kdfVers > 99991231 ) { + ret = false; + } else if ( restrictToCurrent ) { + ret = ( kdfVers <= KeyDerivationFunction.kdfVersion ); + } + if ( ret ) { + return ret; // True + } else { // False, so throw or not. + logger.warning(Logger.SECURITY_FAILURE, "Possible data tampering. Encountered invalid KDF version #. " + + ( throwIfError ? "Throwing IllegalArgumentException" : "" )); + if ( throwIfError ) { + throw new IllegalArgumentException("Version (" + kdfVers + ") invalid. " + + "Must be date in format of YYYYMMDD between " + KeyDerivationFunction.originalVersion + "and 99991231."); + } + } + return false; + } + /** * Prevent public, no-argument CTOR from being auto-generated. Public CTOR * is not needed as all methods are static. */ private CryptoHelper() { - ; // Prevent default CTOR from being auto-created. + ; // Prevent default CTOR from being auto-created. } } diff --git a/src/main/java/org/owasp/esapi/crypto/KeyDerivationFunction.java b/src/main/java/org/owasp/esapi/crypto/KeyDerivationFunction.java index 7535eece2..cc50b5ee8 100644 --- a/src/main/java/org/owasp/esapi/crypto/KeyDerivationFunction.java +++ b/src/main/java/org/owasp/esapi/crypto/KeyDerivationFunction.java @@ -41,55 +41,55 @@ * @since 2.0 */ public class KeyDerivationFunction { - /** - * Used to support backward compatibility. {@code kdfVersion} is used as the - * version for the serialized encrypted ciphertext on all the "encrypt" - * operations. This static field should be the same as - * {@link CipherText#cipherTextVersion} and - * {@link CipherTextSerializer#cipherTextSerializerVersion} to make sure - * that these classes are all kept in-sync in order to support backward - * compatibility of previously encrypted data. - *
    -	 * Previous versions:	20110203 - Original version (ESAPI releases 2.0 & 2.0.1)
    -	 *					    20130830 - Fix to issue #306 (release 2.1.0)
    -	 * 
    - * @see CipherTextSerializer#asSerializedByteArray() - * @see CipherText#asPortableSerializedByteArray() - * @see CipherText#fromPortableSerializedBytes(byte[]) - */ - public static final int originalVersion = 20110203; // First version. Do not change. EVER! - public static final int kdfVersion = 20130830; // Current version. Format: YYYYMMDD, max is 99991231. - private static final long serialVersionUID = kdfVersion; // Format: YYYYMMDD - + /** + * Used to support backward compatibility. {@code kdfVersion} is used as the + * version for the serialized encrypted ciphertext on all the "encrypt" + * operations. This static field should be the same as + * {@link CipherText#cipherTextVersion} and + * {@link CipherTextSerializer#cipherTextSerializerVersion} to make sure + * that these classes are all kept in-sync in order to support backward + * compatibility of previously encrypted data. + *
    +     * Previous versions:    20110203 - Original version (ESAPI releases 2.0 & 2.0.1)
    +     *                        20130830 - Fix to issue #306 (release 2.1.0)
    +     * 
    + * @see CipherTextSerializer#asSerializedByteArray() + * @see CipherText#asPortableSerializedByteArray() + * @see CipherText#fromPortableSerializedBytes(byte[]) + */ + public static final int originalVersion = 20110203; // First version. Do not change. EVER! + public static final int kdfVersion = 20130830; // Current version. Format: YYYYMMDD, max is 99991231. + private static final long serialVersionUID = kdfVersion; // Format: YYYYMMDD + // Pseudo-random function algorithms suitable for NIST KDF in counter mode. - // Note that HmacMD5 is intentionally omitted here!!! + // Note that HmacMD5 is intentionally omitted here!!! public enum PRF_ALGORITHMS { - // SHA-1, 160-bits + // SHA-1, 160-bits HmacSHA1(0, 160, "HmacSHA1"), - // SHA-2 candidates, 256-, 384-, and 512-bits + // SHA-2 candidates, 256-, 384-, and 512-bits HmacSHA256(1, 256, "HmacSHA256"), HmacSHA384(2, 384, "HmacSHA384"), HmacSHA512(3, 512, "HmacSHA512"); - // Reserved for SHA-3 winner, 224-, 256-, 384-, and 512-bits - // Names not yet known. Will use standard JCE alg names here. - // - // E.g., might be something like - // HmacSHA3_224(4, 224, "HmacSHA3-224"), - // HmacSHA3_256(5, 256, "HmacSHA3-256"), - // HmacSHA3_384(6, 384, "HmacSHA3-385"), - // HmacSHA3_512(7, 512, "HmacSHA3-512"); + // Reserved for SHA-3 winner, 224-, 256-, 384-, and 512-bits + // Names not yet known. Will use standard JCE alg names here. + // + // E.g., might be something like + // HmacSHA3_224(4, 224, "HmacSHA3-224"), + // HmacSHA3_256(5, 256, "HmacSHA3-256"), + // HmacSHA3_384(6, 384, "HmacSHA3-385"), + // HmacSHA3_512(7, 512, "HmacSHA3-512"); // Reserved for future use -- values 8 through 15 // Most likely these might be some other strong contenders that // were are based on HMACs from the NIST SHA-3 finalists. - private final byte value; // Value stored in serialized encrypted data to represent PRF + private final byte value; // Value stored in serialized encrypted data to represent PRF private final short bits; private final String algName; PRF_ALGORITHMS(int value, int bits, String algName) { - this.value = (byte) value; - this.bits = (short) bits; - this.algName = algName; + this.value = (byte) value; + this.bits = (short) bits; + this.algName = algName; } public byte getValue() { return value; } @@ -97,11 +97,11 @@ public enum PRF_ALGORITHMS { public String getAlgName() { return algName; } } - private static final Logger logger = ESAPI.getLogger("KeyDerivationFunction"); + private static final Logger logger = ESAPI.getLogger("KeyDerivationFunction"); - private String prfAlg_ = null; - private int version_ = kdfVersion; - private String context_ = ""; + private String prfAlg_ = null; + private int version_ = kdfVersion; + private String context_ = ""; // Check if versions of KeyDerivationFunction, CipherText, and // CipherTextSerializer are all the same. @@ -116,195 +116,195 @@ public enum PRF_ALGORITHMS { } } - /** - * Construct a {@code KeyDerivationFunction}. - * @param prfAlg Specifies a supported algorithm. - */ - public KeyDerivationFunction(KeyDerivationFunction.PRF_ALGORITHMS prfAlg) { - this.prfAlg_ = prfAlg.getAlgName(); - } + /** + * Construct a {@code KeyDerivationFunction}. + * @param prfAlg Specifies a supported algorithm. + */ + public KeyDerivationFunction(KeyDerivationFunction.PRF_ALGORITHMS prfAlg) { + this.prfAlg_ = prfAlg.getAlgName(); + } - /** - * Construct a {@code KeyDerivationFunction} based on the - * ESAPI.property property, {@code Encryptor.KDF.PRF}. - */ - public KeyDerivationFunction() { - String prfName = ESAPI.securityConfiguration().getKDFPseudoRandomFunction(); - if ( ! KeyDerivationFunction.isValidPRF(prfName) ) { - throw new ConfigurationException("Algorithm name " + prfName + - " not a valid algorithm name for property " + - DefaultSecurityConfiguration.KDF_PRF_ALG); - } - prfAlg_ = prfName; - } + /** + * Construct a {@code KeyDerivationFunction} based on the + * ESAPI.property property, {@code Encryptor.KDF.PRF}. + */ + public KeyDerivationFunction() { + String prfName = ESAPI.securityConfiguration().getKDFPseudoRandomFunction(); + if ( ! KeyDerivationFunction.isValidPRF(prfName) ) { + throw new ConfigurationException("Algorithm name " + prfName + + " not a valid algorithm name for property " + + DefaultSecurityConfiguration.KDF_PRF_ALG); + } + prfAlg_ = prfName; + } - /** - * Return the name of the algorithm for the Pseudo Random Function (PRF) - * that is being used. - * @return The PRF algorithm name. - */ - public String getPRFAlgName() { - return prfAlg_; - } - - /** - * Package level method for use by {@code CipherText} class to get default - * - */ - static int getDefaultPRFSelection() { - String prfName = ESAPI.securityConfiguration().getKDFPseudoRandomFunction(); - for (PRF_ALGORITHMS prf : PRF_ALGORITHMS.values()) { - if ( prf.getAlgName().equals(prfName) ) { - return prf.getValue(); - } - } - throw new ConfigurationException("Algorithm name " + prfName + - " not a valid algorithm name for property " + - DefaultSecurityConfiguration.KDF_PRF_ALG); - } - - /** - * Set version so backward compatibility can be supported. Used to set the - * version to some previous version so that previously encrypted data can - * be decrypted. - * @param version Date as a integer, in format of YYYYMMDD. Maximum - * version date is 99991231 (December 31, 9999). - * @throws IllegalArgumentException If {@code version} is not within - * the valid range of [20110203, 99991231]. - */ - public void setVersion(int version) throws IllegalArgumentException { - CryptoHelper.isValidKDFVersion(version, false, true); - this.version_ = version; - } + /** + * Return the name of the algorithm for the Pseudo Random Function (PRF) + * that is being used. + * @return The PRF algorithm name. + */ + public String getPRFAlgName() { + return prfAlg_; + } + + /** + * Package level method for use by {@code CipherText} class to get default + * + */ + static int getDefaultPRFSelection() { + String prfName = ESAPI.securityConfiguration().getKDFPseudoRandomFunction(); + for (PRF_ALGORITHMS prf : PRF_ALGORITHMS.values()) { + if ( prf.getAlgName().equals(prfName) ) { + return prf.getValue(); + } + } + throw new ConfigurationException("Algorithm name " + prfName + + " not a valid algorithm name for property " + + DefaultSecurityConfiguration.KDF_PRF_ALG); + } + + /** + * Set version so backward compatibility can be supported. Used to set the + * version to some previous version so that previously encrypted data can + * be decrypted. + * @param version Date as a integer, in format of YYYYMMDD. Maximum + * version date is 99991231 (December 31, 9999). + * @throws IllegalArgumentException If {@code version} is not within + * the valid range of [20110203, 99991231]. + */ + public void setVersion(int version) throws IllegalArgumentException { + CryptoHelper.isValidKDFVersion(version, false, true); + this.version_ = version; + } - /** - * Return the version used for backward compatibility. - * @return The KDF version #, in format YYYYMMDD, used for supporting - * backward compatibility. - */ - public int getVersion() { - return version_; - } - - - // TODO: IMPORTANT NOTE: In a future release (hopefully starting in 2.3), - // we will be using the 'context' to mix in some additional things. At a - // minimum, we will be using the KDF version (version_) so that downgrade version - // attacks are not possible. Other candidates are the cipher xform and - // the timestamp. - /** - * Set the 'context' as specified by NIST Special Publication 800-108. NIST - * defines 'context' as "A binary string containing the information related - * to the derived keying material. It may include identities of parties who - * are deriving and/or using the derived keying material and, optionally, a - * once known by the parties who derive the keys." NIST SP 800-108 seems to - * imply that while 'context' is recommended, that it is optional. In section - * 7.6 of NIST 800-108, NIST uses "SHOULD" rather than "MUST": - *
    - * "Derived keying material should be bound to all relying - * entities and other information to identify the derived - * keying material. This is called context binding. - * In particular, the identity (or identifier, as the term - * is defined in [NIST SP 800-56A , sic] and [NIST SP - * 800-56B , sic]) of each entity that will access (meaning - * derive, hold, use, and/or distribute) any segment of - * the keying material should be included in the Context - * string input to the KDF, provided that this information - * is known by each entity who derives the keying material." - *
    - * The ISO/IEC's KDF2 uses a similar construction for their KDF and there - * 'context' data is not specified at all. Therefore, ESAPI 2.0's - * reference implementation, {@code JavaEncryptor}, chooses not to use - * 'context' at all. - * - * @param context Optional binary string containing information related to - * the derived keying material. By default (if this method - * is never called), the empty string is used. May have any - * value but {@code null}. - */ - public void setContext(String context) { - if ( context == null ) { - throw new IllegalArgumentException("Context may not be null."); - } - context_ = context; - } - - /** - * Return the optional 'context' that typically contains information - * related to the keying material, such as the identities of the message - * sender and recipient. - * @see #setContext(String) - * @return The 'context' is returned. - */ - public String getContext() { - return context_; - } + /** + * Return the version used for backward compatibility. + * @return The KDF version #, in format YYYYMMDD, used for supporting + * backward compatibility. + */ + public int getVersion() { + return version_; + } + + + // TODO: IMPORTANT NOTE: In a future release (hopefully starting in 2.3), + // we will be using the 'context' to mix in some additional things. At a + // minimum, we will be using the KDF version (version_) so that downgrade version + // attacks are not possible. Other candidates are the cipher xform and + // the timestamp. + /** + * Set the 'context' as specified by NIST Special Publication 800-108. NIST + * defines 'context' as "A binary string containing the information related + * to the derived keying material. It may include identities of parties who + * are deriving and/or using the derived keying material and, optionally, a + * once known by the parties who derive the keys." NIST SP 800-108 seems to + * imply that while 'context' is recommended, that it is optional. In section + * 7.6 of NIST 800-108, NIST uses "SHOULD" rather than "MUST": + *
    + * "Derived keying material should be bound to all relying + * entities and other information to identify the derived + * keying material. This is called context binding. + * In particular, the identity (or identifier, as the term + * is defined in [NIST SP 800-56A , sic] and [NIST SP + * 800-56B , sic]) of each entity that will access (meaning + * derive, hold, use, and/or distribute) any segment of + * the keying material should be included in the Context + * string input to the KDF, provided that this information + * is known by each entity who derives the keying material." + *
    + * The ISO/IEC's KDF2 uses a similar construction for their KDF and there + * 'context' data is not specified at all. Therefore, ESAPI 2.0's + * reference implementation, {@code JavaEncryptor}, chooses not to use + * 'context' at all. + * + * @param context Optional binary string containing information related to + * the derived keying material. By default (if this method + * is never called), the empty string is used. May have any + * value but {@code null}. + */ + public void setContext(String context) { + if ( context == null ) { + throw new IllegalArgumentException("Context may not be null."); + } + context_ = context; + } + + /** + * Return the optional 'context' that typically contains information + * related to the keying material, such as the identities of the message + * sender and recipient. + * @see #setContext(String) + * @return The 'context' is returned. + */ + public String getContext() { + return context_; + } - /** - * The method is ESAPI's Key Derivation Function (KDF) that computes a - * derived key from the {@code keyDerivationKey} for either - * encryption / decryption or for authentication. - *

    - * CAUTION: If this algorithm for computing derived keys from the - * key derivation key is ever changed, we risk breaking backward compatibility of being - * able to decrypt data previously encrypted with earlier / different versions - * of this method. Therefore, do not change this unless you are 100% certain that - * what you are doing will NOT change either of the derived keys for - * ANY "key derivation key" AT ALL!!! - *

    - * NOTE: This method is generally not intended to be called separately. - * It is used by ESAPI's reference crypto implementation class {@code JavaEncryptor} - * and might be useful for someone implementing their own replacement class, but - * generally it is not something that is useful to application client code. - * - * @param keyDerivationKey A key used as an input to a key derivation function - * to derive other keys. This is the key that generally - * is created using some key generation mechanism such as - * {@link CryptoHelper#generateSecretKey(String, int)}. The - * "input" key from which the other keys are derived. - * The derived key will have the same algorithm type - * as this key. This KDK cannot be null. - * @param keySize The cipher's key size (in bits) for the {@code keyDerivationKey}. - * Must have a minimum size of 56 bits and be an integral multiple of 8-bits. - * Note: The derived key will have the same size as this. - * @param purpose The purpose for the derived key. IMPORTANT: For the ESAPI reference implementation, - * {@code JavaEncryptor}, this must be either the string "encryption" or - * "authenticity", where "encryption" is used for creating a derived key to use - * for confidentiality, and "authenticity" is used for creating a derived key to - * use with a MAC to ensure message authenticity. However, since parameter serves - * the same purpose as the "Label" in section 5.1 of NIST SP 800-108, it really can - * be set to anything other than {@code null} or an empty string when called outside - * of ESAPI's {@code JavaEncryptor} reference implementation (but you must consistent). - * @return The derived {@code SecretKey} to be used according - * to the specified purpose. - * @throws NoSuchAlgorithmException The {@code keyDerivationKey} has an unsupported - * encryption algorithm or no current JCE provider supports requested - * Hmac algorithrm used for the PRF for key generation. - * @throws EncryptionException If "UTF-8" is not supported as an encoding, then - * this is thrown with the original {@code UnsupportedEncodingException} - * as the cause. (NOTE: This should never happen as "UTF-8" is supposed to - * be a common encoding supported by all Java implementations. Support - * for it is usually in rt.jar.) This exception is also thrown if the - * requested {@code keySize} parameter exceeds the length of the number of - * bytes provded in the {@code keyDerivationKey} parameter. - * @throws InvalidKeyException Likely indicates a coding error. Should not happen. - * @throws EncryptionException Throw for some precondition violations. - */ - public SecretKey computeDerivedKey(SecretKey keyDerivationKey, int keySize, String purpose) - throws NoSuchAlgorithmException, InvalidKeyException, EncryptionException - { - // Acknowledgments: David Wagner first suggested this approach, I (Kevin Wall) - // stumbled upon NIST SP 800-108 and used it as a basis to - // extend it. Later it was changed that conforms more closely - // to section 5.1 of NIST SP 800-108 based on feedback from - // Jeffrey Walton. - // + /** + * The method is ESAPI's Key Derivation Function (KDF) that computes a + * derived key from the {@code keyDerivationKey} for either + * encryption / decryption or for authentication. + *

    + * CAUTION: If this algorithm for computing derived keys from the + * key derivation key is ever changed, we risk breaking backward compatibility of being + * able to decrypt data previously encrypted with earlier / different versions + * of this method. Therefore, do not change this unless you are 100% certain that + * what you are doing will NOT change either of the derived keys for + * ANY "key derivation key" AT ALL!!! + *

    + * NOTE: This method is generally not intended to be called separately. + * It is used by ESAPI's reference crypto implementation class {@code JavaEncryptor} + * and might be useful for someone implementing their own replacement class, but + * generally it is not something that is useful to application client code. + * + * @param keyDerivationKey A key used as an input to a key derivation function + * to derive other keys. This is the key that generally + * is created using some key generation mechanism such as + * {@link CryptoHelper#generateSecretKey(String, int)}. The + * "input" key from which the other keys are derived. + * The derived key will have the same algorithm type + * as this key. This KDK cannot be null. + * @param keySize The cipher's key size (in bits) for the {@code keyDerivationKey}. + * Must have a minimum size of 56 bits and be an integral multiple of 8-bits. + * Note: The derived key will have the same size as this. + * @param purpose The purpose for the derived key. IMPORTANT: For the ESAPI reference implementation, + * {@code JavaEncryptor}, this must be either the string "encryption" or + * "authenticity", where "encryption" is used for creating a derived key to use + * for confidentiality, and "authenticity" is used for creating a derived key to + * use with a MAC to ensure message authenticity. However, since parameter serves + * the same purpose as the "Label" in section 5.1 of NIST SP 800-108, it really can + * be set to anything other than {@code null} or an empty string when called outside + * of ESAPI's {@code JavaEncryptor} reference implementation (but you must consistent). + * @return The derived {@code SecretKey} to be used according + * to the specified purpose. + * @throws NoSuchAlgorithmException The {@code keyDerivationKey} has an unsupported + * encryption algorithm or no current JCE provider supports requested + * Hmac algorithrm used for the PRF for key generation. + * @throws EncryptionException If "UTF-8" is not supported as an encoding, then + * this is thrown with the original {@code UnsupportedEncodingException} + * as the cause. (NOTE: This should never happen as "UTF-8" is supposed to + * be a common encoding supported by all Java implementations. Support + * for it is usually in rt.jar.) This exception is also thrown if the + * requested {@code keySize} parameter exceeds the length of the number of + * bytes provded in the {@code keyDerivationKey} parameter. + * @throws InvalidKeyException Likely indicates a coding error. Should not happen. + * @throws EncryptionException Throw for some precondition violations. + */ + public SecretKey computeDerivedKey(SecretKey keyDerivationKey, int keySize, String purpose) + throws NoSuchAlgorithmException, InvalidKeyException, EncryptionException + { + // Acknowledgments: David Wagner first suggested this approach, I (Kevin Wall) + // stumbled upon NIST SP 800-108 and used it as a basis to + // extend it. Later it was changed that conforms more closely + // to section 5.1 of NIST SP 800-108 based on feedback from + // Jeffrey Walton. + // - // These checks used to be assertions prior to ESAPI 2.1.0.1 - if ( keyDerivationKey == null ) { - throw new IllegalArgumentException("Key derivation key cannot be null."); - } - // We would choose a larger minimum key size, but we want to allow + // These checks used to be assertions prior to ESAPI 2.1.0.1 + if ( keyDerivationKey == null ) { + throw new IllegalArgumentException("Key derivation key cannot be null."); + } + // We would choose a larger minimum key size, but we want to allow // this KDF to be able to accept DES for legacy encryption needs. (Note that // elsewhere there are checks that disallow *encryption* for key size // less than Encryptor.EncryptionKeyLength bits, so if they want @@ -312,17 +312,17 @@ public SecretKey computeDerivedKey(SecretKey keyDerivationKey, int keySize, Stri // be 56 bits. But I can't think of any valid symmetric encryption // algorithm whose key size is less than 56 bits that we would ever // want to allow. - if ( keySize < 56 ) { - throw new IllegalArgumentException("Key has size of " + keySize + - ", which is less than minimum of 56-bits."); - } - if ( (keySize % 8) != 0 ) { - throw new IllegalArgumentException("Key size (" + keySize + - ") must be a even multiple of 8-bits."); - } - if ( purpose == null || "".equals(purpose) ) { - throw new IllegalArgumentException("Purpose may not be null or empty."); - } + if ( keySize < 56 ) { + throw new IllegalArgumentException("Key has size of " + keySize + + ", which is less than minimum of 56-bits."); + } + if ( (keySize % 8) != 0 ) { + throw new IllegalArgumentException("Key size (" + keySize + + ") must be a even multiple of 8-bits."); + } + if ( purpose == null || "".equals(purpose) ) { + throw new IllegalArgumentException("Purpose may not be null or empty."); + } // // No longer, since we no longer wish to restrict this to use only by JavaEncryptor, so @@ -346,54 +346,54 @@ public SecretKey computeDerivedKey(SecretKey keyDerivationKey, int keySize, Stri providedKeyLen + " bits) to generate key of requested size of " + keySize + " bits."); } - keySize = calcKeySize( keySize ); // Safely convert from bits to a whole # of bytes. - byte[] derivedKey = new byte[ keySize ]; - byte[] label; // Same purpose as NIST SP 800-108's "label" in section 5.1. - byte[] context; // See setContext() for details. - try { - label = purpose.getBytes("UTF-8"); - context = context_.getBytes("UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new EncryptionException("Encryption failure (internal encoding error: UTF-8)", - "UTF-8 encoding is NOT supported as a standard byte encoding: " + e.getMessage(), e); - } - - // Note that keyDerivationKey is going to be some SecretKey like an AES or - // DESede key, but not an HmacSHA1 key. That means it is not likely - // going to be 20 bytes but something different. Experiments show - // that doesn't really matter though as the SecretKeySpec CTOR on - // the following line still returns the appropriate sized key for - // HmacSHA1. So, if keyDerivationKey was originally (say) a 56-bit + keySize = calcKeySize( keySize ); // Safely convert from bits to a whole # of bytes. + byte[] derivedKey = new byte[ keySize ]; + byte[] label; // Same purpose as NIST SP 800-108's "label" in section 5.1. + byte[] context; // See setContext() for details. + try { + label = purpose.getBytes("UTF-8"); + context = context_.getBytes("UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new EncryptionException("Encryption failure (internal encoding error: UTF-8)", + "UTF-8 encoding is NOT supported as a standard byte encoding: " + e.getMessage(), e); + } + + // Note that keyDerivationKey is going to be some SecretKey like an AES or + // DESede key, but not an HmacSHA1 key. That means it is not likely + // going to be 20 bytes but something different. Experiments show + // that doesn't really matter though as the SecretKeySpec CTOR on + // the following line still returns the appropriate sized key for + // HmacSHA1. So, if keyDerivationKey was originally (say) a 56-bit // DES key, then there is apparently some key-stretching going on here // under the hood to create 'sk' so that it is 20 bytes. I cannot vouch // for how secure this key-stretching is. Worse, it might not be specified // as to *how* it is done and left to each JCE provider. - SecretKey sk = new SecretKeySpec(keyDerivationKey.getEncoded(), prfAlg_ ); - Mac mac = null; + SecretKey sk = new SecretKeySpec(keyDerivationKey.getEncoded(), prfAlg_ ); + Mac mac = null; - try { - mac = Mac.getInstance( prfAlg_ ); - mac.init(sk); - } catch( InvalidKeyException ex ) { - logger.error(Logger.SECURITY_FAILURE, - "Created " + prfAlg_ + " Mac but SecretKey sk has alg " + - sk.getAlgorithm(), ex); - throw ex; - } - - // Repeatedly call of PRF Hmac until we've collected enough bits - // for the derived key. The first time through, we calculate the HmacSHA1 - // on the "purpose" string, but subsequent calculations are performed - // on the previous result. - int ctr = 1; // Iteration counter for NIST 800-108 - int totalCopied = 0; - int destPos = 0; - int len = 0; - byte[] tmpKey = null; // Do not declare inside do-while loop!!! - do { - // - // This is to make our KDF more along the line of NIST's. - // NIST's Special Publication 800-108 performs the following in + try { + mac = Mac.getInstance( prfAlg_ ); + mac.init(sk); + } catch( InvalidKeyException ex ) { + logger.error(Logger.SECURITY_FAILURE, + "Created " + prfAlg_ + " Mac but SecretKey sk has alg " + + sk.getAlgorithm(), ex); + throw ex; + } + + // Repeatedly call of PRF Hmac until we've collected enough bits + // for the derived key. The first time through, we calculate the HmacSHA1 + // on the "purpose" string, but subsequent calculations are performed + // on the previous result. + int ctr = 1; // Iteration counter for NIST 800-108 + int totalCopied = 0; + int destPos = 0; + int len = 0; + byte[] tmpKey = null; // Do not declare inside do-while loop!!! + do { + // + // This is to make our KDF more along the line of NIST's. + // NIST's Special Publication 800-108 performs the following in // the iterative loop of Section 5.1: // n := number of blocks required to fulfill request // for i = 1 to n, do @@ -410,35 +410,35 @@ public SecretKey computeDerivedKey(SecretKey keyDerivationKey, int keySize, Stri // optional field (based on NIST's use of the word SHOULD // rather than MUST) // - mac.update( ByteConversionUtil.fromInt( ctr++ ) ); - mac.update(label); - mac.update((byte) '\0'); - mac.update(context); // This is problematic for us. See Jeff Walton's - // analysis of ESAPI 2.0's KDF for details. - // Maybe for 2.1, we'll see; 2.0 too close to GA. - - // According to the Javadoc for Mac.doFinal(byte[]), - // "A call to this method resets this Mac object to the state it was - // in when previously initialized via a call to init(Key) or - // init(Key, AlgorithmParameterSpec). That is, the object is reset - // and available to generate another MAC from the same key, if - // desired, via new calls to update and doFinal." Therefore, we do - // not do an explicit reset(). - tmpKey = mac.doFinal( ByteConversionUtil.fromInt( keySize ) ); - - if ( tmpKey.length >= keySize ) { - len = keySize; - } else { - len = Math.min(tmpKey.length, keySize - totalCopied); - } - System.arraycopy(tmpKey, 0, derivedKey, destPos, len); - label = tmpKey; - totalCopied += tmpKey.length; - destPos += len; - } while( totalCopied < keySize ); - - // Don't leave remnants of the partial key in memory. (Note: we could - // not do this if tmpKey were declared in the do-while loop. + mac.update( ByteConversionUtil.fromInt( ctr++ ) ); + mac.update(label); + mac.update((byte) '\0'); + mac.update(context); // This is problematic for us. See Jeff Walton's + // analysis of ESAPI 2.0's KDF for details. + // Maybe for 2.1, we'll see; 2.0 too close to GA. + + // According to the Javadoc for Mac.doFinal(byte[]), + // "A call to this method resets this Mac object to the state it was + // in when previously initialized via a call to init(Key) or + // init(Key, AlgorithmParameterSpec). That is, the object is reset + // and available to generate another MAC from the same key, if + // desired, via new calls to update and doFinal." Therefore, we do + // not do an explicit reset(). + tmpKey = mac.doFinal( ByteConversionUtil.fromInt( keySize ) ); + + if ( tmpKey.length >= keySize ) { + len = keySize; + } else { + len = Math.min(tmpKey.length, keySize - totalCopied); + } + System.arraycopy(tmpKey, 0, derivedKey, destPos, len); + label = tmpKey; + totalCopied += tmpKey.length; + destPos += len; + } while( totalCopied < keySize ); + + // Don't leave remnants of the partial key in memory. (Note: we could + // not do this if tmpKey were declared in the do-while loop. // Of course, in reality, trying to stomp these bits out is probably not // realistic because the JIT is likely toing to be smart enough to // optimze this loop away. We probably could try to outsmart it, by @@ -448,48 +448,48 @@ public SecretKey computeDerivedKey(SecretKey keyDerivationKey, int keySize, Stri // to a serious limitation in Java and many other languages that one // cannot arbitrarily disable the optimizer either at compile time or // run time because of security reasons. Sigh. At least we've tried. - for ( int i = 0; i < tmpKey.length; i++ ) { - tmpKey[i] = '\0'; - } - tmpKey = null; // Make it immediately eligible for GC. - + for ( int i = 0; i < tmpKey.length; i++ ) { + tmpKey[i] = '\0'; + } + tmpKey = null; // Make it immediately eligible for GC. + // Convert it back into a SecretKey of the appropriate type. - return new SecretKeySpec(derivedKey, keyDerivationKey.getAlgorithm()); - } + return new SecretKeySpec(derivedKey, keyDerivationKey.getAlgorithm()); + } - /** - * Check if specified algorithm name is a valid PRF that can be used. - * @param prfAlgName Name of the PRF algorithm; e.g., "HmacSHA1", "HmacSHA384", etc. - * @return True if {@code prfAlgName} is supported, otherwise false. - */ - public static boolean isValidPRF(String prfAlgName) { - for (PRF_ALGORITHMS prf : PRF_ALGORITHMS.values()) { - if ( prf.getAlgName().equals(prfAlgName) ) { - return true; - } - } - return false; - } + /** + * Check if specified algorithm name is a valid PRF that can be used. + * @param prfAlgName Name of the PRF algorithm; e.g., "HmacSHA1", "HmacSHA384", etc. + * @return True if {@code prfAlgName} is supported, otherwise false. + */ + public static boolean isValidPRF(String prfAlgName) { + for (PRF_ALGORITHMS prf : PRF_ALGORITHMS.values()) { + if ( prf.getAlgName().equals(prfAlgName) ) { + return true; + } + } + return false; + } - public static PRF_ALGORITHMS convertNameToPRF(String prfAlgName) { - for (PRF_ALGORITHMS prf : PRF_ALGORITHMS.values()) { - if ( prf.getAlgName().equals(prfAlgName) ) { - return prf; - } - } - throw new IllegalArgumentException("Algorithm name " + prfAlgName + - " not a valid PRF algorithm name for the ESAPI KDF."); - } - - public static PRF_ALGORITHMS convertIntToPRF(int selection) { - for (PRF_ALGORITHMS prf : PRF_ALGORITHMS.values()) { - if ( prf.getValue() == selection ) { - return prf; - } - } - throw new IllegalArgumentException("No KDF PRF algorithm found for value name " + selection); - } - + public static PRF_ALGORITHMS convertNameToPRF(String prfAlgName) { + for (PRF_ALGORITHMS prf : PRF_ALGORITHMS.values()) { + if ( prf.getAlgName().equals(prfAlgName) ) { + return prf; + } + } + throw new IllegalArgumentException("Algorithm name " + prfAlgName + + " not a valid PRF algorithm name for the ESAPI KDF."); + } + + public static PRF_ALGORITHMS convertIntToPRF(int selection) { + for (PRF_ALGORITHMS prf : PRF_ALGORITHMS.values()) { + if ( prf.getValue() == selection ) { + return prf; + } + } + throw new IllegalArgumentException("No KDF PRF algorithm found for value name " + selection); + } + /** * Calculate the size of a key. The key size is given in bits, but we * can only allocate them by octets (i.e., bytes), so make sure we @@ -522,11 +522,11 @@ private static int calcKeySize(int ks) { * * @param args Required, but not used. */ - public static final void main(String args[]) { - System.out.println("Supported pseudo-random functions for KDF (version: " + kdfVersion + ")"); - System.out.println("Enum Name\tAlgorithm\t# bits"); - for (PRF_ALGORITHMS prf : PRF_ALGORITHMS.values()) { - System.out.println(prf + "\t" + prf.getAlgName() + "\t" + prf.getBits()); - } - } + public static final void main(String args[]) { + System.out.println("Supported pseudo-random functions for KDF (version: " + kdfVersion + ")"); + System.out.println("Enum Name\tAlgorithm\t# bits"); + for (PRF_ALGORITHMS prf : PRF_ALGORITHMS.values()) { + System.out.println(prf + "\t" + prf.getAlgName() + "\t" + prf.getBits()); + } + } } diff --git a/src/main/java/org/owasp/esapi/crypto/PlainText.java b/src/main/java/org/owasp/esapi/crypto/PlainText.java index d70dd98f5..5f504cba1 100644 --- a/src/main/java/org/owasp/esapi/crypto/PlainText.java +++ b/src/main/java/org/owasp/esapi/crypto/PlainText.java @@ -29,74 +29,74 @@ */ public final class PlainText implements Serializable { - private static final long serialVersionUID = 20090921; - private static Logger logger = ESAPI.getLogger("PlainText"); - - private byte[] rawBytes = null; - - /** - * Construct a {@code PlainText} object from a {@code String}. - * @param str The {@code String} that is converted to a UTF-8 encoded - * byte array to create the {@code PlainText} object. - * @throws IllegalArgumentException If {@code str} argument is null. - */ - public PlainText(String str) { - try { - if ( str == null ) { - throw new IllegalArgumentException("String for plaintext may not be null!"); - } - rawBytes = str.getBytes("UTF-8"); - } catch (UnsupportedEncodingException e) { - // Should never happen. - logger.error(Logger.EVENT_FAILURE, "PlainText(String) CTOR failed: Can't find UTF-8 byte-encoding!", e); - throw new RuntimeException("Can't find UTF-8 byte-encoding!", e); - } - } + private static final long serialVersionUID = 20090921; + private static Logger logger = ESAPI.getLogger("PlainText"); + + private byte[] rawBytes = null; + + /** + * Construct a {@code PlainText} object from a {@code String}. + * @param str The {@code String} that is converted to a UTF-8 encoded + * byte array to create the {@code PlainText} object. + * @throws IllegalArgumentException If {@code str} argument is null. + */ + public PlainText(String str) { + try { + if ( str == null ) { + throw new IllegalArgumentException("String for plaintext may not be null!"); + } + rawBytes = str.getBytes("UTF-8"); + } catch (UnsupportedEncodingException e) { + // Should never happen. + logger.error(Logger.EVENT_FAILURE, "PlainText(String) CTOR failed: Can't find UTF-8 byte-encoding!", e); + throw new RuntimeException("Can't find UTF-8 byte-encoding!", e); + } + } - /** - * Construct a {@code PlainText} object from a {@code byte} array. - * @param b The {@code byte} array used to create the {@code PlainText} - * object. - */ - public PlainText(byte[] b) { - // Must allow 0 length arrays though, to represent empty strings. - if ( b == null ) { + /** + * Construct a {@code PlainText} object from a {@code byte} array. + * @param b The {@code byte} array used to create the {@code PlainText} + * object. + */ + public PlainText(byte[] b) { + // Must allow 0 length arrays though, to represent empty strings. + if ( b == null ) { throw new IllegalArgumentException("Byte array representing plaintext cannot be null."); } // Make copy so mutable byte array b can't change PlainText. - rawBytes = new byte[ b.length ]; - System.arraycopy(b, 0, rawBytes, 0, b.length); - } - - /** - * Convert the {@code PlainText} object to a UTF-8 encoded {@code String}. - * @return A {@code String} representing the {@code PlainText} object. - */ - public String toString() { - try { - return new String(rawBytes, "UTF-8"); - } catch (UnsupportedEncodingException e) { - // Should never happen. - logger.error(Logger.EVENT_FAILURE, "PlainText.toString() failed: Can't find UTF-8 byte-encoding!", e); - throw new RuntimeException("Can't find UTF-8 byte-encoding!", e); - } - } - - /** - * Convert the {@code PlainText} object to a byte array. - * @return A byte array representing the {@code PlainText} object. - */ - public byte[] asBytes() { - byte[] bytes = new byte[ rawBytes.length ]; - System.arraycopy(rawBytes, 0, bytes, 0, rawBytes.length); - return bytes; - } - - /** - * {@inheritDoc} - */ - @Override public boolean equals(Object anObject) { + rawBytes = new byte[ b.length ]; + System.arraycopy(b, 0, rawBytes, 0, b.length); + } + + /** + * Convert the {@code PlainText} object to a UTF-8 encoded {@code String}. + * @return A {@code String} representing the {@code PlainText} object. + */ + public String toString() { + try { + return new String(rawBytes, "UTF-8"); + } catch (UnsupportedEncodingException e) { + // Should never happen. + logger.error(Logger.EVENT_FAILURE, "PlainText.toString() failed: Can't find UTF-8 byte-encoding!", e); + throw new RuntimeException("Can't find UTF-8 byte-encoding!", e); + } + } + + /** + * Convert the {@code PlainText} object to a byte array. + * @return A byte array representing the {@code PlainText} object. + */ + public byte[] asBytes() { + byte[] bytes = new byte[ rawBytes.length ]; + System.arraycopy(rawBytes, 0, bytes, 0, rawBytes.length); + return bytes; + } + + /** + * {@inheritDoc} + */ + @Override public boolean equals(Object anObject) { if ( this == anObject ) return true; if ( anObject == null ) return false; @@ -108,42 +108,42 @@ public byte[] asBytes() { ); } return result; - } - - /** - * Same as {@code this.toString().hashCode()}. - * @return {@code this.toString().hashCode()}. - */ - @Override public int hashCode() { - return this.toString().hashCode(); - } - - /** - * Return the length of the UTF-8 encoded byte array representing this - * object. Note that if this object was constructed with the constructor - * {@code PlainText(String str)}, then this length might not necessarily - * agree with {@code str.length()}. - * - * @return The length of the UTF-8 encoded byte array representing this - * object. - */ - public int length() { - return rawBytes.length; - } - - // DISCUSS: Should we set 'rawBytes' to null??? Won't make it eligible for - // GC unless this PlainText object is set to null which can't do - // from here. If we set it to null, most methods will cause - // NullPointerException to be thrown. Also will have to change a - // lot of JUnit tests. - /** - * First overwrite the bytes of plaintext with the character '*'. - */ - public void overwrite() { - CryptoHelper.overwrite( rawBytes ); - // rawBytes = null; // See above comment re: discussion. - } - + } + + /** + * Same as {@code this.toString().hashCode()}. + * @return {@code this.toString().hashCode()}. + */ + @Override public int hashCode() { + return this.toString().hashCode(); + } + + /** + * Return the length of the UTF-8 encoded byte array representing this + * object. Note that if this object was constructed with the constructor + * {@code PlainText(String str)}, then this length might not necessarily + * agree with {@code str.length()}. + * + * @return The length of the UTF-8 encoded byte array representing this + * object. + */ + public int length() { + return rawBytes.length; + } + + // DISCUSS: Should we set 'rawBytes' to null??? Won't make it eligible for + // GC unless this PlainText object is set to null which can't do + // from here. If we set it to null, most methods will cause + // NullPointerException to be thrown. Also will have to change a + // lot of JUnit tests. + /** + * First overwrite the bytes of plaintext with the character '*'. + */ + public void overwrite() { + CryptoHelper.overwrite( rawBytes ); + // rawBytes = null; // See above comment re: discussion. + } + /** * Needed for correct definition of equals for general classes. * (Technically not needed for 'final' classes though like this class diff --git a/src/main/java/org/owasp/esapi/crypto/SecurityProviderLoader.java b/src/main/java/org/owasp/esapi/crypto/SecurityProviderLoader.java index 6639f1357..cd4efd34e 100644 --- a/src/main/java/org/owasp/esapi/crypto/SecurityProviderLoader.java +++ b/src/main/java/org/owasp/esapi/crypto/SecurityProviderLoader.java @@ -47,7 +47,7 @@ public class SecurityProviderLoader { // IBMJCE is default for WebSphere and is used by IBM JDKs. They // also have IBMJCEFIPS, but not sure if this is *always* provided // with WebSphere or just an add-on, hence not including it. IBMJCEFIPS - // is a FIPS 140-2 compliant JCE provider from IBM. + // is a FIPS 140-2 compliant JCE provider from IBM. jceProviders.put("IBMJCE", "com.ibm.crypto.provider.IBMJCE"); // jceProviders.put("IBMJCEFIPS", "com.ibm.crypto.fips.provider.IBMJCEFIPS"); @@ -209,13 +209,13 @@ public static int insertProviderAt(String algProvider, int pos) // compliant JCE provider at the first position and it was // already loaded at position 3, then this is not FIPS 140-2 // compliant. Therefore, we make it a warning and a failure. - // Also log separately using 'always' in case warnings suppressed - // as per NSA suggestion. + // Also log separately using 'always' in case warnings suppressed + // as per NSA suggestion. logger.warning(Logger.SECURITY_FAILURE, msg); logger.always(Logger.SECURITY_FAILURE, "(audit) " + msg); } } else { - // As per NSA suggestion. + // As per NSA suggestion. logger.always(Logger.SECURITY_AUDIT, "Successfully loaded preferred JCE provider " + algProvider + " at position " + pos); @@ -223,12 +223,12 @@ public static int insertProviderAt(String algProvider, int pos) return ret; } catch(SecurityException ex) { // CHECKME: Log security event here too? This is a RuntimeException. - // It would only be thrown if a SecurityManager is installed that - // prohibits Security.addProvider() or Security.insertProviderAt() - // by the current user of this thread. Will log it here. Can always - // be ignored. - logger.always(Logger.SECURITY_FAILURE, "Failed to load preferred JCE provider " + - algProvider + " at position " + pos, ex); + // It would only be thrown if a SecurityManager is installed that + // prohibits Security.addProvider() or Security.insertProviderAt() + // by the current user of this thread. Will log it here. Can always + // be ignored. + logger.always(Logger.SECURITY_FAILURE, "Failed to load preferred JCE provider " + + algProvider + " at position " + pos, ex); throw ex; } catch(Exception ex) { // Possibilities include: ClassNotFoundException, @@ -236,8 +236,8 @@ public static int insertProviderAt(String algProvider, int pos) // // Log an error & re-throw original message as NoSuchProviderException, // since that what it probably really implied here. This probably a configuration - // error (e.g., classpath problem, etc.) so we use EVENT_FAILURE rather than - // SECURITY_FAILURE here. + // error (e.g., classpath problem, etc.) so we use EVENT_FAILURE rather than + // SECURITY_FAILURE here. logger.error(Logger.EVENT_FAILURE, "Failed to insert failed crypto " + " provider " + algProvider + " at position " + pos, ex); throw new NoSuchProviderException("Failed to insert crypto " + @@ -272,7 +272,7 @@ public static int loadESAPIPreferredJCEProvider() throws NoSuchProviderException try { // If unset or set to empty string, then don't try to change it. if ( prefJCEProvider == null || prefJCEProvider.trim().length() == 0) { - // Always log, per NSA suggestion. + // Always log, per NSA suggestion. logger.always(Logger.SECURITY_AUDIT, "No Encryptor.PreferredJCEProvider specified."); return -1; // Unchanged; it is, whatever it is. } else { @@ -280,8 +280,8 @@ public static int loadESAPIPreferredJCEProvider() throws NoSuchProviderException } } catch (NoSuchProviderException ex) { // Will already have logged with exception msg. - String msg = "failed to load *preferred* " + "JCE crypto provider, " + prefJCEProvider; - logger.always(Logger.SECURITY_AUDIT, msg); // Per NSA suggestion. + String msg = "failed to load *preferred* " + "JCE crypto provider, " + prefJCEProvider; + logger.always(Logger.SECURITY_AUDIT, msg); // Per NSA suggestion. logger.error(Logger.SECURITY_FAILURE, msg); throw ex; } diff --git a/src/main/java/org/owasp/esapi/errors/AccessControlException.java b/src/main/java/org/owasp/esapi/errors/AccessControlException.java index 96eaf80c5..197f12d96 100644 --- a/src/main/java/org/owasp/esapi/errors/AccessControlException.java +++ b/src/main/java/org/owasp/esapi/errors/AccessControlException.java @@ -23,35 +23,35 @@ */ public class AccessControlException extends EnterpriseSecurityException { - /** The Constant serialVersionUID. */ - private static final long serialVersionUID = 1L; + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 1L; - /** - * Instantiates a new access control exception. - */ - protected AccessControlException() { - // hidden - } + /** + * Instantiates a new access control exception. + */ + protected AccessControlException() { + // hidden + } - /** - * Creates a new instance of {@code AccessControlException}. + /** + * Creates a new instance of {@code AccessControlException}. * * @param userMessage * @param logMessage */ - public AccessControlException(String userMessage, String logMessage) { - super(userMessage, logMessage); - } + public AccessControlException(String userMessage, String logMessage) { + super(userMessage, logMessage); + } - /** - * Instantiates a new access control exception. - * - * @param userMessage the message displayed to the user - * @param logMessage the message logged - * @param cause the root cause - */ - public AccessControlException(String userMessage, String logMessage, Throwable cause) { - super(userMessage, logMessage, cause); - } + /** + * Instantiates a new access control exception. + * + * @param userMessage the message displayed to the user + * @param logMessage the message logged + * @param cause the root cause + */ + public AccessControlException(String userMessage, String logMessage, Throwable cause) { + super(userMessage, logMessage, cause); + } } diff --git a/src/main/java/org/owasp/esapi/errors/AuthenticationAccountsException.java b/src/main/java/org/owasp/esapi/errors/AuthenticationAccountsException.java index c81ff844b..d59fa6911 100644 --- a/src/main/java/org/owasp/esapi/errors/AuthenticationAccountsException.java +++ b/src/main/java/org/owasp/esapi/errors/AuthenticationAccountsException.java @@ -24,36 +24,36 @@ */ public class AuthenticationAccountsException extends AuthenticationException { - /** The Constant serialVersionUID. */ - private static final long serialVersionUID = 1L; + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 1L; - /** - * Instantiates a new authentication exception. - */ - protected AuthenticationAccountsException() { - // hidden - } + /** + * Instantiates a new authentication exception. + */ + protected AuthenticationAccountsException() { + // hidden + } - /** - * Creates a new instance of {@code AuthenticationAccountsException}. - * - * @param userMessage the message displayed to the user - * @param logMessage the message logged - * - */ - public AuthenticationAccountsException(String userMessage, String logMessage) { - super(userMessage, logMessage); - } + /** + * Creates a new instance of {@code AuthenticationAccountsException}. + * + * @param userMessage the message displayed to the user + * @param logMessage the message logged + * + */ + public AuthenticationAccountsException(String userMessage, String logMessage) { + super(userMessage, logMessage); + } - /** - * Instantiates a new authentication exception. - * - * @param userMessage the message displayed to the user - * @param logMessage the message logged - * @param cause the root cause - */ - public AuthenticationAccountsException(String userMessage, String logMessage, Throwable cause) { - super(userMessage, logMessage, cause); - } + /** + * Instantiates a new authentication exception. + * + * @param userMessage the message displayed to the user + * @param logMessage the message logged + * @param cause the root cause + */ + public AuthenticationAccountsException(String userMessage, String logMessage, Throwable cause) { + super(userMessage, logMessage, cause); + } } diff --git a/src/main/java/org/owasp/esapi/errors/AuthenticationCredentialsException.java b/src/main/java/org/owasp/esapi/errors/AuthenticationCredentialsException.java index e48187739..c50019cf5 100644 --- a/src/main/java/org/owasp/esapi/errors/AuthenticationCredentialsException.java +++ b/src/main/java/org/owasp/esapi/errors/AuthenticationCredentialsException.java @@ -24,35 +24,35 @@ */ public class AuthenticationCredentialsException extends AuthenticationException { - /** The Constant serialVersionUID. */ - private static final long serialVersionUID = 1L; + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 1L; - /** - * Instantiates a new authentication exception. - */ - protected AuthenticationCredentialsException() { - // hidden - } + /** + * Instantiates a new authentication exception. + */ + protected AuthenticationCredentialsException() { + // hidden + } - /** - * Creates a new instance of {@code AuthenticationCredentialsException}. - * - * @param userMessage the message displayed to the user - * @param logMessage the message logged - */ - public AuthenticationCredentialsException(String userMessage, String logMessage) { - super(userMessage, logMessage); - } + /** + * Creates a new instance of {@code AuthenticationCredentialsException}. + * + * @param userMessage the message displayed to the user + * @param logMessage the message logged + */ + public AuthenticationCredentialsException(String userMessage, String logMessage) { + super(userMessage, logMessage); + } - /** - * Instantiates a new authentication exception. - * - * @param userMessage the message displayed to the user - * @param logMessage the message logged - * @param cause the root cause - */ - public AuthenticationCredentialsException(String userMessage, String logMessage, Throwable cause) { - super(userMessage, logMessage, cause); - } + /** + * Instantiates a new authentication exception. + * + * @param userMessage the message displayed to the user + * @param logMessage the message logged + * @param cause the root cause + */ + public AuthenticationCredentialsException(String userMessage, String logMessage, Throwable cause) { + super(userMessage, logMessage, cause); + } } diff --git a/src/main/java/org/owasp/esapi/errors/AuthenticationException.java b/src/main/java/org/owasp/esapi/errors/AuthenticationException.java index c8198f57f..0f350bad9 100644 --- a/src/main/java/org/owasp/esapi/errors/AuthenticationException.java +++ b/src/main/java/org/owasp/esapi/errors/AuthenticationException.java @@ -24,15 +24,15 @@ */ public class AuthenticationException extends EnterpriseSecurityException { - /** The Constant serialVersionUID. */ - private static final long serialVersionUID = 1L; + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 1L; - /** - * Instantiates a new authentication exception. - */ - protected AuthenticationException() { - // hidden - } + /** + * Instantiates a new authentication exception. + */ + protected AuthenticationException() { + // hidden + } /** * Creates a new instance of {@code AuthenticationException}. diff --git a/src/main/java/org/owasp/esapi/errors/AuthenticationHostException.java b/src/main/java/org/owasp/esapi/errors/AuthenticationHostException.java index 1deac4b72..1e5fe2577 100644 --- a/src/main/java/org/owasp/esapi/errors/AuthenticationHostException.java +++ b/src/main/java/org/owasp/esapi/errors/AuthenticationHostException.java @@ -23,35 +23,35 @@ */ public class AuthenticationHostException extends AuthenticationException { - /** The Constant serialVersionUID. */ - private static final long serialVersionUID = 1L; + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 1L; - /** - * Instantiates a new authentication exception. - */ - protected AuthenticationHostException() { - // hidden - } + /** + * Instantiates a new authentication exception. + */ + protected AuthenticationHostException() { + // hidden + } - /** - * Creates a new instance of AuthenticationHostException. - * - * @param userMessage the message displayed to the user - * @param logMessage the message logged - */ - public AuthenticationHostException(String userMessage, String logMessage) { - super(userMessage, logMessage); - } + /** + * Creates a new instance of AuthenticationHostException. + * + * @param userMessage the message displayed to the user + * @param logMessage the message logged + */ + public AuthenticationHostException(String userMessage, String logMessage) { + super(userMessage, logMessage); + } - /** - * Instantiates a new authentication exception. - * - * @param userMessage the message displayed to the user - * @param logMessage the message logged - * @param cause the cause - */ - public AuthenticationHostException(String userMessage, String logMessage, Throwable cause) { - super(userMessage, logMessage, cause); - } + /** + * Instantiates a new authentication exception. + * + * @param userMessage the message displayed to the user + * @param logMessage the message logged + * @param cause the cause + */ + public AuthenticationHostException(String userMessage, String logMessage, Throwable cause) { + super(userMessage, logMessage, cause); + } } diff --git a/src/main/java/org/owasp/esapi/errors/AuthenticationLoginException.java b/src/main/java/org/owasp/esapi/errors/AuthenticationLoginException.java index d389591bc..3d63400fb 100644 --- a/src/main/java/org/owasp/esapi/errors/AuthenticationLoginException.java +++ b/src/main/java/org/owasp/esapi/errors/AuthenticationLoginException.java @@ -24,35 +24,35 @@ */ public class AuthenticationLoginException extends AuthenticationException { - /** The Constant serialVersionUID. */ - private static final long serialVersionUID = 1L; + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 1L; - /** - * Instantiates a new authentication exception. - */ - protected AuthenticationLoginException() { - // hidden - } + /** + * Instantiates a new authentication exception. + */ + protected AuthenticationLoginException() { + // hidden + } - /** - * Creates a new instance of EnterpriseSecurityException. - * - * @param userMessage the message displayed to the user - * @param logMessage the message logged - */ - public AuthenticationLoginException(String userMessage, String logMessage) { - super(userMessage, logMessage); - } + /** + * Creates a new instance of EnterpriseSecurityException. + * + * @param userMessage the message displayed to the user + * @param logMessage the message logged + */ + public AuthenticationLoginException(String userMessage, String logMessage) { + super(userMessage, logMessage); + } - /** - * Instantiates a new authentication exception. - * - * @param userMessage the message displayed to the user - * @param logMessage the message logged - * @param cause the cause - */ - public AuthenticationLoginException(String userMessage, String logMessage, Throwable cause) { - super(userMessage, logMessage, cause); - } + /** + * Instantiates a new authentication exception. + * + * @param userMessage the message displayed to the user + * @param logMessage the message logged + * @param cause the cause + */ + public AuthenticationLoginException(String userMessage, String logMessage, Throwable cause) { + super(userMessage, logMessage, cause); + } } diff --git a/src/main/java/org/owasp/esapi/errors/AvailabilityException.java b/src/main/java/org/owasp/esapi/errors/AvailabilityException.java index 3ec04b677..7c7a17e02 100644 --- a/src/main/java/org/owasp/esapi/errors/AvailabilityException.java +++ b/src/main/java/org/owasp/esapi/errors/AvailabilityException.java @@ -24,15 +24,15 @@ */ public class AvailabilityException extends EnterpriseSecurityException { - /** The Constant serialVersionUID. */ - private static final long serialVersionUID = 1L; + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 1L; - /** - * Instantiates a new availability exception. - */ - protected AvailabilityException() { - // hidden - } + /** + * Instantiates a new availability exception. + */ + protected AvailabilityException() { + // hidden + } /** * Creates a new instance of AvailabilityException. diff --git a/src/main/java/org/owasp/esapi/errors/CertificateException.java b/src/main/java/org/owasp/esapi/errors/CertificateException.java index 2f84b2c01..ee98f2dc1 100644 --- a/src/main/java/org/owasp/esapi/errors/CertificateException.java +++ b/src/main/java/org/owasp/esapi/errors/CertificateException.java @@ -23,15 +23,15 @@ */ public class CertificateException extends EnterpriseSecurityException { - /** The Constant serialVersionUID. */ - private static final long serialVersionUID = 1L; + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 1L; - /** - * Instantiates a new certificate exception. - */ - protected CertificateException() { - // hidden - } + /** + * Instantiates a new certificate exception. + */ + protected CertificateException() { + // hidden + } /** * Creates a new instance of CertificateException. diff --git a/src/main/java/org/owasp/esapi/errors/ConfigurationException.java b/src/main/java/org/owasp/esapi/errors/ConfigurationException.java index 4e6a38130..c6173f418 100644 --- a/src/main/java/org/owasp/esapi/errors/ConfigurationException.java +++ b/src/main/java/org/owasp/esapi/errors/ConfigurationException.java @@ -14,21 +14,21 @@ */ public class ConfigurationException extends RuntimeException { - protected static final long serialVersionUID = 1L; + protected static final long serialVersionUID = 1L; - public ConfigurationException(Exception e) { - super(e); - } + public ConfigurationException(Exception e) { + super(e); + } - public ConfigurationException(String s) { - super(s); - } - - public ConfigurationException(String s, Throwable cause) { - super(s, cause); - } - - public ConfigurationException(Throwable cause) { - super(cause); - } + public ConfigurationException(String s) { + super(s); + } + + public ConfigurationException(String s, Throwable cause) { + super(s, cause); + } + + public ConfigurationException(Throwable cause) { + super(cause); + } } diff --git a/src/main/java/org/owasp/esapi/errors/EncodingException.java b/src/main/java/org/owasp/esapi/errors/EncodingException.java index f2b269445..9c53d0d1c 100644 --- a/src/main/java/org/owasp/esapi/errors/EncodingException.java +++ b/src/main/java/org/owasp/esapi/errors/EncodingException.java @@ -23,15 +23,15 @@ */ public class EncodingException extends EnterpriseSecurityException { - /** The Constant serialVersionUID. */ - private static final long serialVersionUID = 1L; + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 1L; - /** - * Instantiates a new service exception. - */ - protected EncodingException() { - // hidden - } + /** + * Instantiates a new service exception. + */ + protected EncodingException() { + // hidden + } /** * Creates a new instance of EncodingException. @@ -39,7 +39,7 @@ protected EncodingException() { * @param userMessage * the message displayed to the user * @param logMessage - * the message logged + * the message logged */ public EncodingException(String userMessage, String logMessage) { super(userMessage, logMessage); @@ -51,7 +51,7 @@ public EncodingException(String userMessage, String logMessage) { * @param userMessage * the message displayed to the user * @param logMessage - * the message logged + * the message logged * @param cause * the cause */ diff --git a/src/main/java/org/owasp/esapi/errors/EncryptionException.java b/src/main/java/org/owasp/esapi/errors/EncryptionException.java index 163a1d228..8a70fe70d 100644 --- a/src/main/java/org/owasp/esapi/errors/EncryptionException.java +++ b/src/main/java/org/owasp/esapi/errors/EncryptionException.java @@ -23,15 +23,15 @@ */ public class EncryptionException extends EnterpriseSecurityException { - /** The Constant serialVersionUID. */ - private static final long serialVersionUID = 1L; + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 1L; - /** - * Instantiates a new EncryptionException. - */ - protected EncryptionException() { - // hidden - } + /** + * Instantiates a new EncryptionException. + */ + protected EncryptionException() { + // hidden + } /** * Creates a new instance of EncryptionException. @@ -39,7 +39,7 @@ protected EncryptionException() { * @param userMessage * the message displayed to the user * @param logMessage - * the message logged + * the message logged */ public EncryptionException(String userMessage, String logMessage) { super(userMessage, logMessage); @@ -51,7 +51,7 @@ public EncryptionException(String userMessage, String logMessage) { * @param userMessage * the message displayed to the user * @param logMessage - * the message logged + * the message logged * @param cause * the cause */ diff --git a/src/main/java/org/owasp/esapi/errors/EncryptionRuntimeException.java b/src/main/java/org/owasp/esapi/errors/EncryptionRuntimeException.java index 466ef5cb1..1b46d383f 100644 --- a/src/main/java/org/owasp/esapi/errors/EncryptionRuntimeException.java +++ b/src/main/java/org/owasp/esapi/errors/EncryptionRuntimeException.java @@ -25,15 +25,15 @@ */ public class EncryptionRuntimeException extends EnterpriseSecurityRuntimeException { - /** The Constant serialVersionUID. */ - private static final long serialVersionUID = 1L; + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 1L; - /** - * Instantiates a new EncryptionException. - */ - protected EncryptionRuntimeException() { - // hidden - } + /** + * Instantiates a new EncryptionException. + */ + protected EncryptionRuntimeException() { + // hidden + } /** * Creates a new instance of EncryptionException. @@ -41,7 +41,7 @@ protected EncryptionRuntimeException() { * @param userMessage * the message displayed to the user * @param logMessage - * the message logged + * the message logged */ public EncryptionRuntimeException(String userMessage, String logMessage) { super(userMessage, logMessage); @@ -53,7 +53,7 @@ public EncryptionRuntimeException(String userMessage, String logMessage) { * @param userMessage * the message displayed to the user * @param logMessage - * the message logged + * the message logged * @param cause * the cause */ diff --git a/src/main/java/org/owasp/esapi/errors/EnterpriseSecurityException.java b/src/main/java/org/owasp/esapi/errors/EnterpriseSecurityException.java index da03ef29f..1be227524 100644 --- a/src/main/java/org/owasp/esapi/errors/EnterpriseSecurityException.java +++ b/src/main/java/org/owasp/esapi/errors/EnterpriseSecurityException.java @@ -97,15 +97,15 @@ protected EnterpriseSecurityException(String userMessage, Throwable cause) * context of the exception. * * @param userMessage - * the message displayed to the user + * the message displayed to the user * @param logMessage - * the message logged + * the message logged */ public EnterpriseSecurityException(String userMessage, String logMessage) { - super(userMessage); + super(userMessage); this.logMessage = logMessage; if (!ESAPI.securityConfiguration().getBooleanProp( DISABLE_INTRUSION_DETECTION )) { - ESAPI.intrusionDetector().addException(this); + ESAPI.intrusionDetector().addException(this); } } @@ -117,16 +117,16 @@ public EnterpriseSecurityException(String userMessage, String logMessage) { * context of the exception. * * @param userMessage - * the message displayed to the user + * the message displayed to the user * @param logMessage - * the message logged + * the message logged * @param cause the cause */ public EnterpriseSecurityException(String userMessage, String logMessage, Throwable cause) { super(userMessage, cause); this.logMessage = logMessage; if (!ESAPI.securityConfiguration().getBooleanProp( DISABLE_INTRUSION_DETECTION )) { - ESAPI.intrusionDetector().addException(this); + ESAPI.intrusionDetector().addException(this); } } diff --git a/src/main/java/org/owasp/esapi/errors/EnterpriseSecurityRuntimeException.java b/src/main/java/org/owasp/esapi/errors/EnterpriseSecurityRuntimeException.java index 6dab2a54c..8097bcdf0 100644 --- a/src/main/java/org/owasp/esapi/errors/EnterpriseSecurityRuntimeException.java +++ b/src/main/java/org/owasp/esapi/errors/EnterpriseSecurityRuntimeException.java @@ -93,15 +93,15 @@ protected EnterpriseSecurityRuntimeException(String userMessage, * context of the exception. * * @param userMessage - * the message displayed to the user + * the message displayed to the user * @param logMessage - * the message logged + * the message logged */ public EnterpriseSecurityRuntimeException(String userMessage, String logMessage) { - super(userMessage); + super(userMessage); this.logMessage = logMessage; if (!ESAPI.securityConfiguration().getDisableIntrusionDetection()) { - ESAPI.intrusionDetector().addException(this); + ESAPI.intrusionDetector().addException(this); } } @@ -113,16 +113,16 @@ public EnterpriseSecurityRuntimeException(String userMessage, String logMessage) * context of the exception. * * @param userMessage - * the message displayed to the user + * the message displayed to the user * @param logMessage - * the message logged + * the message logged * @param cause the cause */ public EnterpriseSecurityRuntimeException(String userMessage, String logMessage, Throwable cause) { super(userMessage, cause); this.logMessage = logMessage; if (!ESAPI.securityConfiguration().getDisableIntrusionDetection()) { - ESAPI.intrusionDetector().addException(this); + ESAPI.intrusionDetector().addException(this); } } diff --git a/src/main/java/org/owasp/esapi/errors/ExecutorException.java b/src/main/java/org/owasp/esapi/errors/ExecutorException.java index a27c74fa3..5676e1eb9 100644 --- a/src/main/java/org/owasp/esapi/errors/ExecutorException.java +++ b/src/main/java/org/owasp/esapi/errors/ExecutorException.java @@ -23,15 +23,15 @@ */ public class ExecutorException extends EnterpriseSecurityException { - /** The Constant serialVersionUID. */ - private static final long serialVersionUID = 1L; + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 1L; - /** - * Instantiates a new ExecutorException. - */ - protected ExecutorException() { - // hidden - } + /** + * Instantiates a new ExecutorException. + */ + protected ExecutorException() { + // hidden + } /** * Creates a new instance of ExecutorException. @@ -39,7 +39,7 @@ protected ExecutorException() { * @param userMessage * the message to display to users * @param logMessage - * the message logged + * the message logged */ public ExecutorException(String userMessage, String logMessage) { super(userMessage, logMessage); @@ -51,7 +51,7 @@ public ExecutorException(String userMessage, String logMessage) { * @param userMessage * the message to display to users * @param logMessage - * the message logged + * the message logged * @param cause * the cause */ diff --git a/src/main/java/org/owasp/esapi/errors/IntegrityException.java b/src/main/java/org/owasp/esapi/errors/IntegrityException.java index 59d97a189..07fad5adc 100644 --- a/src/main/java/org/owasp/esapi/errors/IntegrityException.java +++ b/src/main/java/org/owasp/esapi/errors/IntegrityException.java @@ -24,15 +24,15 @@ */ public class IntegrityException extends EnterpriseSecurityException { - /** The Constant serialVersionUID. */ - private static final long serialVersionUID = 1L; + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 1L; - /** - * Instantiates a new availability exception. - */ - protected IntegrityException() { - // hidden - } + /** + * Instantiates a new availability exception. + */ + protected IntegrityException() { + // hidden + } /** * Creates a new instance of IntegrityException. @@ -40,7 +40,7 @@ protected IntegrityException() { * @param userMessage * the message to display to users * @param logMessage - * the message logged + * the message logged */ public IntegrityException(String userMessage, String logMessage) { super(userMessage, logMessage); @@ -52,7 +52,7 @@ public IntegrityException(String userMessage, String logMessage) { * @param userMessage * the message to display to users * @param logMessage - * the message logged + * the message logged * @param cause * the cause */ diff --git a/src/main/java/org/owasp/esapi/errors/IntrusionException.java b/src/main/java/org/owasp/esapi/errors/IntrusionException.java index b5253ea28..472e3076b 100644 --- a/src/main/java/org/owasp/esapi/errors/IntrusionException.java +++ b/src/main/java/org/owasp/esapi/errors/IntrusionException.java @@ -47,7 +47,7 @@ public class IntrusionException extends EnterpriseSecurityRuntimeException { * @param userMessage * the message to display to users * @param logMessage - * the message logged + * the message logged */ public IntrusionException(String userMessage, String logMessage) { super(userMessage); @@ -61,9 +61,9 @@ public IntrusionException(String userMessage, String logMessage) { * @param userMessage * the message to display to users * @param logMessage - * the message logged + * the message logged * @param cause - * the cause + * the cause */ public IntrusionException(String userMessage, String logMessage, Throwable cause) { super(userMessage, cause); diff --git a/src/main/java/org/owasp/esapi/errors/ValidationAvailabilityException.java b/src/main/java/org/owasp/esapi/errors/ValidationAvailabilityException.java index 4e4a1d48b..02136dab6 100644 --- a/src/main/java/org/owasp/esapi/errors/ValidationAvailabilityException.java +++ b/src/main/java/org/owasp/esapi/errors/ValidationAvailabilityException.java @@ -20,38 +20,38 @@ */ public class ValidationAvailabilityException extends ValidationException { - /** The Constant serialVersionUID. */ - private static final long serialVersionUID = 1L; + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 1L; - /** - * Instantiates a new validation exception. - */ - protected ValidationAvailabilityException() { - // hidden - } + /** + * Instantiates a new validation exception. + */ + protected ValidationAvailabilityException() { + // hidden + } /** * Create a new ValidationException * @param userMessage * the message to display to users * @param logMessage - * the message logged + * the message logged */ - public ValidationAvailabilityException(String userMessage, String logMessage) { - super(userMessage, logMessage); - } + public ValidationAvailabilityException(String userMessage, String logMessage) { + super(userMessage, logMessage); + } /** * Create a new ValidationException * @param userMessage * the message to display to users * @param logMessage - * the message logged + * the message logged * @param cause - * the cause - */ - public ValidationAvailabilityException(String userMessage, String logMessage, Throwable cause) { - super(userMessage, logMessage, cause); - } + * the cause + */ + public ValidationAvailabilityException(String userMessage, String logMessage, Throwable cause) { + super(userMessage, logMessage, cause); + } } diff --git a/src/main/java/org/owasp/esapi/errors/ValidationException.java b/src/main/java/org/owasp/esapi/errors/ValidationException.java index a33562f96..b93990890 100644 --- a/src/main/java/org/owasp/esapi/errors/ValidationException.java +++ b/src/main/java/org/owasp/esapi/errors/ValidationException.java @@ -26,15 +26,15 @@ public class ValidationException extends EnterpriseSecurityException { protected static final long serialVersionUID = 1L; - /** The UI reference that caused this ValidationException */ - private String context; + /** The UI reference that caused this ValidationException */ + private String context; - /** - * Instantiates a new validation exception. - */ - protected ValidationException() { - // hidden - } + /** + * Instantiates a new validation exception. + */ + protected ValidationException() { + // hidden + } /** * Creates a new instance of ValidationException. @@ -42,7 +42,7 @@ protected ValidationException() { * @param userMessage * the message to display to users * @param logMessage - * the message logged + * the message logged */ public ValidationException(String userMessage, String logMessage) { super(userMessage, logMessage); @@ -54,7 +54,7 @@ public ValidationException(String userMessage, String logMessage) { * @param userMessage * the message to display to users * @param logMessage - * the message logged + * the message logged * @param cause * the cause */ @@ -68,7 +68,7 @@ public ValidationException(String userMessage, String logMessage, Throwable caus * @param userMessage * the message to display to users * @param logMessage - * the message logged + * the message logged * @param context * the source that caused this exception */ @@ -83,7 +83,7 @@ public ValidationException(String userMessage, String logMessage, String context * @param userMessage * the message to display to users * @param logMessage - * the message logged + * the message logged * @param cause * the cause * @param context @@ -91,25 +91,25 @@ public ValidationException(String userMessage, String logMessage, String context */ public ValidationException(String userMessage, String logMessage, Throwable cause, String context) { super(userMessage, logMessage, cause); - setContext(context); + setContext(context); } - /** - * Returns the UI reference that caused this ValidationException - * - * @return context, the source that caused the exception, stored as a string - */ - public String getContext() { - return context; - } + /** + * Returns the UI reference that caused this ValidationException + * + * @return context, the source that caused the exception, stored as a string + */ + public String getContext() { + return context; + } - /** - * Set's the UI reference that caused this ValidationException - * - * @param context - * the context to set, passed as a String - */ - public void setContext(String context) { - this.context = context; - } + /** + * Set's the UI reference that caused this ValidationException + * + * @param context + * the context to set, passed as a String + */ + public void setContext(String context) { + this.context = context; + } } diff --git a/src/main/java/org/owasp/esapi/errors/ValidationUploadException.java b/src/main/java/org/owasp/esapi/errors/ValidationUploadException.java index 4a04de2eb..41e2e7ce8 100644 --- a/src/main/java/org/owasp/esapi/errors/ValidationUploadException.java +++ b/src/main/java/org/owasp/esapi/errors/ValidationUploadException.java @@ -20,15 +20,15 @@ */ public class ValidationUploadException extends ValidationException { - /** The Constant serialVersionUID. */ - private static final long serialVersionUID = 1L; + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 1L; - /** - * Instantiates a new validation exception. - */ - protected ValidationUploadException() { - // hidden - } + /** + * Instantiates a new validation exception. + */ + protected ValidationUploadException() { + // hidden + } /** * Create a new ValidationException @@ -36,11 +36,11 @@ protected ValidationUploadException() { * @param userMessage * the message to display to users * @param logMessage - * the message logged + * the message logged */ - public ValidationUploadException(String userMessage, String logMessage) { - super(userMessage, logMessage); - } + public ValidationUploadException(String userMessage, String logMessage) { + super(userMessage, logMessage); + } /** * Create a new ValidationException @@ -48,12 +48,12 @@ public ValidationUploadException(String userMessage, String logMessage) { * @param userMessage * the message to display to users * @param logMessage - * the message logged + * the message logged * @param cause - * the cause + * the cause */ - public ValidationUploadException(String userMessage, String logMessage, Throwable cause) { - super(userMessage, logMessage, cause); - } + public ValidationUploadException(String userMessage, String logMessage, Throwable cause) { + super(userMessage, logMessage, cause); + } } diff --git a/src/main/java/org/owasp/esapi/filters/ClickjackFilter.java b/src/main/java/org/owasp/esapi/filters/ClickjackFilter.java index c57b836b5..bbfabf1e4 100644 --- a/src/main/java/org/owasp/esapi/filters/ClickjackFilter.java +++ b/src/main/java/org/owasp/esapi/filters/ClickjackFilter.java @@ -63,46 +63,46 @@ public class ClickjackFilter implements Filter { - private String mode = "DENY"; + private String mode = "DENY"; - /** - * Initialize "mode" parameter from web.xml. Valid values are "DENY" and "SAMEORIGIN". - * If you leave this parameter out, the default is to use the DENY mode. - * - * @param filterConfig A filter configuration object used by a servlet container - * to pass information to a filter during initialization. - */ - public void init(FilterConfig filterConfig) { - String configMode = filterConfig.getInitParameter("mode"); - if ( configMode != null && ( configMode.equals( "DENY" ) || configMode.equals( "SAMEORIGIN" ) ) ) { - mode = configMode; - } - } - - /** - * Add X-FRAME-OPTIONS response header to tell IE8 (and any other browsers who - * decide to implement) not to display this content in a frame. For details, please - * refer to - * @link http://blogs.msdn.com/sdl/archive/2009/02/05/clickjacking-defense-in-ie8.aspx - * - * @param request The request object. - * @param response The response object. - * @param chain Refers to the {@code FilterChain} object to pass control to the - * next {@code Filter}. - * @throws IOException - * @throws ServletException - */ - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException - { + /** + * Initialize "mode" parameter from web.xml. Valid values are "DENY" and "SAMEORIGIN". + * If you leave this parameter out, the default is to use the DENY mode. + * + * @param filterConfig A filter configuration object used by a servlet container + * to pass information to a filter during initialization. + */ + public void init(FilterConfig filterConfig) { + String configMode = filterConfig.getInitParameter("mode"); + if ( configMode != null && ( configMode.equals( "DENY" ) || configMode.equals( "SAMEORIGIN" ) ) ) { + mode = configMode; + } + } + + /** + * Add X-FRAME-OPTIONS response header to tell IE8 (and any other browsers who + * decide to implement) not to display this content in a frame. For details, please + * refer to + * @link http://blogs.msdn.com/sdl/archive/2009/02/05/clickjacking-defense-in-ie8.aspx + * + * @param request The request object. + * @param response The response object. + * @param chain Refers to the {@code FilterChain} object to pass control to the + * next {@code Filter}. + * @throws IOException + * @throws ServletException + */ + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException + { HttpServletResponse res = (HttpServletResponse)response; res.addHeader("X-FRAME-OPTIONS", mode ); chain.doFilter(request, response); - } + } - /** - * {@inheritDoc} - */ - public void destroy() { - } - + /** + * {@inheritDoc} + */ + public void destroy() { + } + } diff --git a/src/main/java/org/owasp/esapi/filters/ESAPIFilter.java b/src/main/java/org/owasp/esapi/filters/ESAPIFilter.java index 347743938..f38e7fae4 100644 --- a/src/main/java/org/owasp/esapi/filters/ESAPIFilter.java +++ b/src/main/java/org/owasp/esapi/filters/ESAPIFilter.java @@ -37,18 +37,18 @@ */ public class ESAPIFilter implements Filter { - private final Logger logger = ESAPI.getLogger("ESAPIFilter"); + private final Logger logger = ESAPI.getLogger("ESAPIFilter"); - private static final String[] obfuscate = { "password" }; + private static final String[] obfuscate = { "password" }; - private String loginPage = "WEB-INF/login.jsp"; + private String loginPage = "WEB-INF/login.jsp"; private String publicUnauthorizedLandingPage = "WEB-INF/index.jsp"; - /** - * Called by the web container to indicate to a filter that it is being - * placed into service. The servlet container calls the init method exactly - * once after instantiating the filter. The init method must complete - * successfully before the filter is asked to do any filtering work. + /** + * Called by the web container to indicate to a filter that it is being + * placed into service. The servlet container calls the init method exactly + * once after instantiating the filter. The init method must complete + * successfully before the filter is asked to do any filtering work. *

    * Init parameters in web.xml for this filter: *

      @@ -59,104 +59,104 @@ public class ESAPIFilter implements Filter { * Default is "WEB-INF/index.jsp". *
    *

    - * - * @param filterConfig - * configuration object - */ - public void init(FilterConfig filterConfig) { - String path = filterConfig.getInitParameter("resourceDirectory"); - if ( path != null ) { - ESAPI.securityConfiguration().setResourceDirectory( path ); - } - String paramLoginPage = filterConfig.getInitParameter("loginPage"); - if ( paramLoginPage != null ) { - loginPage = paramLoginPage; - } + * + * @param filterConfig + * configuration object + */ + public void init(FilterConfig filterConfig) { + String path = filterConfig.getInitParameter("resourceDirectory"); + if ( path != null ) { + ESAPI.securityConfiguration().setResourceDirectory( path ); + } + String paramLoginPage = filterConfig.getInitParameter("loginPage"); + if ( paramLoginPage != null ) { + loginPage = paramLoginPage; + } String paramUnauthorizedPage = filterConfig.getInitParameter("publicUnauthorizedLandingPage"); if ( paramUnauthorizedPage != null ) { publicUnauthorizedLandingPage = paramUnauthorizedPage; } - } - - /** - * The doFilter method of the Filter is called by the container each time a - * request/response pair is passed through the chain due to a client request - * for a resource at the end of the chain. The FilterChain passed in to this - * method allows the Filter to pass on the request and response to the next - * entity in the chain. - * - * @param req - * Request object to be processed - * @param resp - * Response object - * @param chain - * current FilterChain - * @exception IOException - * if any occurs - */ - public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException { - HttpServletRequest request = (HttpServletRequest) req; - HttpServletResponse response = (HttpServletResponse) resp; - ESAPI.httpUtilities().setCurrentHTTP(request, response); - - try { - // figure out who the current user is - try { - ESAPI.authenticator().login(request, response); - } catch( AuthenticationException e ) { - ESAPI.authenticator().logout(); - request.setAttribute("message", "Authentication failed"); - RequestDispatcher dispatcher = request.getRequestDispatcher(loginPage); - dispatcher.forward(request, response); - return; - } - - // log this request, obfuscating any parameter named password - ESAPI.httpUtilities().logHTTPRequest(request, logger, Arrays.asList(obfuscate)); - - // check access to this URL - if ( !ESAPI.accessController().isAuthorizedForURL(request.getRequestURI()) ) { - request.setAttribute("message", "Unauthorized" ); - RequestDispatcher dispatcher = request.getRequestDispatcher(publicUnauthorizedLandingPage); - dispatcher.forward(request, response); - return; - } - - // check for CSRF attacks - // ESAPI.httpUtilities().checkCSRFToken(); - - // forward this request on to the web application - chain.doFilter(request, response); - - // set up response with content type - ESAPI.httpUtilities().setContentType( response ); + } + + /** + * The doFilter method of the Filter is called by the container each time a + * request/response pair is passed through the chain due to a client request + * for a resource at the end of the chain. The FilterChain passed in to this + * method allows the Filter to pass on the request and response to the next + * entity in the chain. + * + * @param req + * Request object to be processed + * @param resp + * Response object + * @param chain + * current FilterChain + * @exception IOException + * if any occurs + */ + public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException { + HttpServletRequest request = (HttpServletRequest) req; + HttpServletResponse response = (HttpServletResponse) resp; + ESAPI.httpUtilities().setCurrentHTTP(request, response); + + try { + // figure out who the current user is + try { + ESAPI.authenticator().login(request, response); + } catch( AuthenticationException e ) { + ESAPI.authenticator().logout(); + request.setAttribute("message", "Authentication failed"); + RequestDispatcher dispatcher = request.getRequestDispatcher(loginPage); + dispatcher.forward(request, response); + return; + } + + // log this request, obfuscating any parameter named password + ESAPI.httpUtilities().logHTTPRequest(request, logger, Arrays.asList(obfuscate)); + + // check access to this URL + if ( !ESAPI.accessController().isAuthorizedForURL(request.getRequestURI()) ) { + request.setAttribute("message", "Unauthorized" ); + RequestDispatcher dispatcher = request.getRequestDispatcher(publicUnauthorizedLandingPage); + dispatcher.forward(request, response); + return; + } + + // check for CSRF attacks + // ESAPI.httpUtilities().checkCSRFToken(); + + // forward this request on to the web application + chain.doFilter(request, response); + + // set up response with content type + ESAPI.httpUtilities().setContentType( response ); // set no-cache headers on every response // only do this if the entire site should not be cached // otherwise you should do this strategically in your controller or actions - ESAPI.httpUtilities().setNoCacheHeaders( response ); + ESAPI.httpUtilities().setNoCacheHeaders( response ); + + } catch (Exception e) { + logger.error( Logger.SECURITY_FAILURE, "Error in ESAPI security filter: " + e.getMessage(), e ); + request.setAttribute("message", e.getMessage() ); - } catch (Exception e) { - logger.error( Logger.SECURITY_FAILURE, "Error in ESAPI security filter: " + e.getMessage(), e ); - request.setAttribute("message", e.getMessage() ); - - } finally { - // VERY IMPORTANT - // clear out the ThreadLocal variables in the authenticator - // some containers could possibly reuse this thread without clearing the User - ESAPI.clearCurrent(); - } - } - - /** - * Called by the web container to indicate to a filter that it is being - * taken out of service. This method is only called once all threads within - * the filter's doFilter method have exited or after a timeout period has - * passed. After the web container calls this method, it will not call the - * doFilter method again on this instance of the filter. - */ - public void destroy() { - // finalize - } + } finally { + // VERY IMPORTANT + // clear out the ThreadLocal variables in the authenticator + // some containers could possibly reuse this thread without clearing the User + ESAPI.clearCurrent(); + } + } + + /** + * Called by the web container to indicate to a filter that it is being + * taken out of service. This method is only called once all threads within + * the filter's doFilter method have exited or after a timeout period has + * passed. After the web container calls this method, it will not call the + * doFilter method again on this instance of the filter. + */ + public void destroy() { + // finalize + } } diff --git a/src/main/java/org/owasp/esapi/filters/SecurityWrapper.java b/src/main/java/org/owasp/esapi/filters/SecurityWrapper.java index 82d6ce1f4..9180a8018 100644 --- a/src/main/java/org/owasp/esapi/filters/SecurityWrapper.java +++ b/src/main/java/org/owasp/esapi/filters/SecurityWrapper.java @@ -121,8 +121,8 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha * */ public void destroy() { - // no special action - } + // no special action + } /** * @@ -130,7 +130,7 @@ public void destroy() { * @throws javax.servlet.ServletException */ public void init(FilterConfig filterConfig) throws ServletException { - this.allowableResourcesRoot = StringUtilities.replaceNull( filterConfig.getInitParameter( "allowableResourcesRoot" ), allowableResourcesRoot ); - } - + this.allowableResourcesRoot = StringUtilities.replaceNull( filterConfig.getInitParameter( "allowableResourcesRoot" ), allowableResourcesRoot ); + } + } diff --git a/src/main/java/org/owasp/esapi/logging/java/JavaLogFactory.java b/src/main/java/org/owasp/esapi/logging/java/JavaLogFactory.java index 3a43c2c93..016c37dde 100644 --- a/src/main/java/org/owasp/esapi/logging/java/JavaLogFactory.java +++ b/src/main/java/org/owasp/esapi/logging/java/JavaLogFactory.java @@ -96,7 +96,7 @@ public class JavaLogFactory implements LogFactory { } logManager.readConfiguration(stream); } catch (IOException ioe) { - throw new ConfigurationException("Failed to load esapi-java-logging.properties.", ioe); + throw new ConfigurationException("Failed to load esapi-java-logging.properties.", ioe); } } diff --git a/src/main/java/org/owasp/esapi/logging/java/JavaLogLevelHandlers.java b/src/main/java/org/owasp/esapi/logging/java/JavaLogLevelHandlers.java index cce498680..69c03f9e9 100644 --- a/src/main/java/org/owasp/esapi/logging/java/JavaLogLevelHandlers.java +++ b/src/main/java/org/owasp/esapi/logging/java/JavaLogLevelHandlers.java @@ -19,34 +19,34 @@ public enum JavaLogLevelHandlers implements JavaLogLevelHandler { - SEVERE(Level.SEVERE), - WARNING(Level.WARNING), - INFO(Level.INFO), - CONFIG(Level.CONFIG), - FINE(Level.FINE), - FINER(Level.FINER), - FINEST(Level.FINEST), - ALWAYS(ESAPICustomJavaLevel.ALWAYS_LEVEL), - ERROR(ESAPICustomJavaLevel.ERROR_LEVEL); + SEVERE(Level.SEVERE), + WARNING(Level.WARNING), + INFO(Level.INFO), + CONFIG(Level.CONFIG), + FINE(Level.FINE), + FINER(Level.FINER), + FINEST(Level.FINEST), + ALWAYS(ESAPICustomJavaLevel.ALWAYS_LEVEL), + ERROR(ESAPICustomJavaLevel.ERROR_LEVEL); - private final Level level; - - private JavaLogLevelHandlers(Level lvl) { - this.level = lvl; - } - - @Override - public boolean isEnabled(Logger logger) { - return logger.isLoggable(level); - } + private final Level level; + + private JavaLogLevelHandlers(Level lvl) { + this.level = lvl; + } + + @Override + public boolean isEnabled(Logger logger) { + return logger.isLoggable(level); + } - @Override - public void log(Logger logger, String msg) { - logger.log(level, msg); - } + @Override + public void log(Logger logger, String msg) { + logger.log(level, msg); + } - @Override - public void log(Logger logger, String msg, Throwable th) { - logger.log(level, msg, th); - } + @Override + public void log(Logger logger, String msg, Throwable th) { + logger.log(level, msg, th); + } } diff --git a/src/main/java/org/owasp/esapi/logging/log4j/Log4JLoggerFactory.java b/src/main/java/org/owasp/esapi/logging/log4j/Log4JLoggerFactory.java index bfa0914a3..931ae6267 100644 --- a/src/main/java/org/owasp/esapi/logging/log4j/Log4JLoggerFactory.java +++ b/src/main/java/org/owasp/esapi/logging/log4j/Log4JLoggerFactory.java @@ -59,7 +59,7 @@ public Log4JLoggerFactory() {} * @param name The class name to return a logger for. * @return org.owasp.esapi.reference.Log4JLogger */ - public org.apache.log4j.Logger makeNewLoggerInstance(String name) { + public org.apache.log4j.Logger makeNewLoggerInstance(String name) { return new EsapiLog4JWrapper(name); } @@ -67,7 +67,7 @@ public org.apache.log4j.Logger makeNewLoggerInstance(String name) { public static class EsapiLog4JWrapper extends org.apache.log4j.Logger { protected EsapiLog4JWrapper(String name) { - super(name); + super(name); } @Override diff --git a/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogBridgeImpl.java b/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogBridgeImpl.java index 79e13dc7b..a6c7d1730 100644 --- a/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogBridgeImpl.java +++ b/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogBridgeImpl.java @@ -58,7 +58,7 @@ public void log(Logger logger, int esapiLevel, EventType type, String message) { throw new IllegalArgumentException("Unable to lookup SLF4J level mapping for esapi value of " + esapiLevel); } if (handler.isEnabled(logger)) { - String fullMessage = appender.appendTo(logger.getName(), type, message); + String fullMessage = appender.appendTo(logger.getName(), type, message); String cleanString = scrubber.cleanMessage(fullMessage); Marker typeMarker = MARKER_FACTORY.getMarker(type.toString()); @@ -72,7 +72,7 @@ public void log(Logger logger, int esapiLevel, EventType type, String message, T throw new IllegalArgumentException("Unable to lookup SLF4J level mapping for esapi value of " + esapiLevel); } if (handler.isEnabled(logger)) { - String fullMessage = appender.appendTo(logger.getName(), type, message); + String fullMessage = appender.appendTo(logger.getName(), type, message); String cleanString = scrubber.cleanMessage(fullMessage); Marker typeMarker = MARKER_FACTORY.getMarker(type.toString()); diff --git a/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogFactory.java b/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogFactory.java index fab645062..85341b2df 100644 --- a/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogFactory.java +++ b/src/main/java/org/owasp/esapi/logging/slf4j/Slf4JLogFactory.java @@ -60,9 +60,9 @@ public class Slf4JLogFactory implements LogFactory { boolean logUserInfo = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_USER_INFO); boolean logClientInfo = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_CLIENT_INFO); - boolean logApplicationName = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_APPLICATION_NAME); - String appName = ESAPI.securityConfiguration().getStringProp(DefaultSecurityConfiguration.APPLICATION_NAME); - boolean logServerIp = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_SERVER_IP); + boolean logApplicationName = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_APPLICATION_NAME); + String appName = ESAPI.securityConfiguration().getStringProp(DefaultSecurityConfiguration.APPLICATION_NAME); + boolean logServerIp = ESAPI.securityConfiguration().getBooleanProp(DefaultSecurityConfiguration.LOG_SERVER_IP); SLF4J_LOG_APPENDER = createLogAppender(logUserInfo, logClientInfo, logServerIp, logApplicationName, appName); Map levelLookup = new HashMap<>(); diff --git a/src/main/java/org/owasp/esapi/reference/AbstractAccessReferenceMap.java b/src/main/java/org/owasp/esapi/reference/AbstractAccessReferenceMap.java index 4bd77af42..4e988c45b 100644 --- a/src/main/java/org/owasp/esapi/reference/AbstractAccessReferenceMap.java +++ b/src/main/java/org/owasp/esapi/reference/AbstractAccessReferenceMap.java @@ -89,13 +89,13 @@ public AbstractAccessReferenceMap( int initialSize ) { * @param directReferences * the direct references * @deprecated This constructor internally calls the abstract method - * {@link #getUniqueReference()}. Since this is a constructor, any - * subclass that implements getUniqueReference() has not had it's - * own constructor run. This leads to strange bugs because subclass - * internal state is initializaed after calls to getUniqueReference() - * have already happened. If this constructor is desired in a - * subclass, consider running {@link #update(Set)} in the subclass - * constructor instead. + * {@link #getUniqueReference()}. Since this is a constructor, any + * subclass that implements getUniqueReference() has not had it's + * own constructor run. This leads to strange bugs because subclass + * internal state is initializaed after calls to getUniqueReference() + * have already happened. If this constructor is desired in a + * subclass, consider running {@link #update(Set)} in the subclass + * constructor instead. */ @Deprecated public AbstractAccessReferenceMap( Set directReferences ) { @@ -118,13 +118,13 @@ public AbstractAccessReferenceMap( Set directReferences ) { * The initial size to set the map to. * * @deprecated This constructor internally calls the abstract method - * {@link #getUniqueReference()}. Since this is a constructor, any - * subclass that implements getUniqueReference() has not had it's - * own constructor run. This leads to strange bugs because subclass - * internal state is initializaed after calls to getUniqueReference() - * have already happened. If this constructor is desired in a - * subclass, consider running {@link #update(Set)} in the subclass - * constructor instead. + * {@link #getUniqueReference()}. Since this is a constructor, any + * subclass that implements getUniqueReference() has not had it's + * own constructor run. This leads to strange bugs because subclass + * internal state is initializaed after calls to getUniqueReference() + * have already happened. If this constructor is desired in a + * subclass, consider running {@link #update(Set)} in the subclass + * constructor instead. */ @Deprecated public AbstractAccessReferenceMap( Set directReferences, int initialSize ) { diff --git a/src/main/java/org/owasp/esapi/reference/AbstractAuthenticator.java b/src/main/java/org/owasp/esapi/reference/AbstractAuthenticator.java index e6976c7ac..c412a3be1 100644 --- a/src/main/java/org/owasp/esapi/reference/AbstractAuthenticator.java +++ b/src/main/java/org/owasp/esapi/reference/AbstractAuthenticator.java @@ -23,7 +23,7 @@ */ public abstract class AbstractAuthenticator implements org.owasp.esapi.Authenticator { - /** + /** * Key for user in session */ protected static final String USER = "ESAPIUserSessionKey"; @@ -54,13 +54,13 @@ public void setUser(User newUser) { } } - /** - * - */ - public AbstractAuthenticator() { - super(); - } - + /** + * + */ + public AbstractAuthenticator() { + super(); + } + /** * {@inheritDoc} */ @@ -96,8 +96,8 @@ public User getCurrentUser() { * @return the user from session or null if no user is found in the session */ protected User getUserFromSession() { - HTTPUtilities httpUtils = ESAPI.httpUtilities(); - HttpServletRequest req = httpUtils.getCurrentRequest(); + HTTPUtilities httpUtils = ESAPI.httpUtilities(); + HttpServletRequest req = httpUtils.getCurrentRequest(); HttpSession session = req.getSession(false); if (session == null) return null; return ESAPI.httpUtilities().getSessionAttribute(USER); @@ -114,7 +114,7 @@ protected User getUserFromSession() { */ protected DefaultUser getUserFromRememberToken() { try { - HTTPUtilities utils =ESAPI.httpUtilities(); + HTTPUtilities utils =ESAPI.httpUtilities(); String token = utils.getCookie(ESAPI.currentRequest(), HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME); if (token == null) return null; diff --git a/src/main/java/org/owasp/esapi/reference/DefaultAccessController.java b/src/main/java/org/owasp/esapi/reference/DefaultAccessController.java index 5e8adf98a..23b80ebb0 100644 --- a/src/main/java/org/owasp/esapi/reference/DefaultAccessController.java +++ b/src/main/java/org/owasp/esapi/reference/DefaultAccessController.java @@ -11,7 +11,7 @@ import org.owasp.esapi.reference.accesscontrol.policyloader.PolicyDTO; public class DefaultAccessController implements AccessController { - private Map ruleMap; + private Map ruleMap; private static volatile AccessController singletonInstance = null; @@ -26,122 +26,122 @@ public static AccessController getInstance() throws AccessControlException { return singletonInstance; } - protected final Logger logger = ESAPI.getLogger("DefaultAccessController"); + protected final Logger logger = ESAPI.getLogger("DefaultAccessController"); - private DefaultAccessController() throws AccessControlException { - ACRPolicyFileLoader policyDescriptor = new ACRPolicyFileLoader(); - PolicyDTO policyDTO = policyDescriptor.load(); - ruleMap = policyDTO.getAccessControlRules(); - } + private DefaultAccessController() throws AccessControlException { + ACRPolicyFileLoader policyDescriptor = new ACRPolicyFileLoader(); + PolicyDTO policyDTO = policyDescriptor.load(); + ruleMap = policyDTO.getAccessControlRules(); + } /** * {@inheritDoc} */ - public boolean isAuthorized(Object key, Object runtimeParameter) { - try { - AccessControlRule rule = (AccessControlRule)ruleMap.get(key); - if(rule == null) { - throw new AccessControlException("Access Denied", - "AccessControlRule was not found for key: " + key); - } - if(logger.isDebugEnabled()){ logger.debug(Logger.EVENT_SUCCESS, "Evaluating Authorization Rule \"" + key + "\" Using class: " + rule.getClass().getCanonicalName()); } - return rule.isAuthorized(runtimeParameter); - } catch(Exception e) { - try { - //Log the exception by throwing and then catching it. - //TODO figure out what which string goes where. - throw new AccessControlException("Access Denied", - "An unhandled Exception was " + - "caught, so access is denied.", - e); - } catch(AccessControlException ace) { - //the exception was just logged. There's nothing left to do. - } - return false; //fail closed - } - } + public boolean isAuthorized(Object key, Object runtimeParameter) { + try { + AccessControlRule rule = (AccessControlRule)ruleMap.get(key); + if(rule == null) { + throw new AccessControlException("Access Denied", + "AccessControlRule was not found for key: " + key); + } + if(logger.isDebugEnabled()){ logger.debug(Logger.EVENT_SUCCESS, "Evaluating Authorization Rule \"" + key + "\" Using class: " + rule.getClass().getCanonicalName()); } + return rule.isAuthorized(runtimeParameter); + } catch(Exception e) { + try { + //Log the exception by throwing and then catching it. + //TODO figure out what which string goes where. + throw new AccessControlException("Access Denied", + "An unhandled Exception was " + + "caught, so access is denied.", + e); + } catch(AccessControlException ace) { + //the exception was just logged. There's nothing left to do. + } + return false; //fail closed + } + } /** {@inheritDoc} */ - public void assertAuthorized(Object key, Object runtimeParameter) throws AccessControlException { - boolean isAuthorized; - try { - AccessControlRule rule = (AccessControlRule)ruleMap.get(key); - if(rule == null) { - throw new AccessControlException("Access Denied", - "AccessControlRule was not found for key: " + key); - } - if(logger.isDebugEnabled()){ logger.debug(Logger.EVENT_SUCCESS, "Asserting Authorization Rule \"" + key + "\" Using class: " + rule.getClass().getCanonicalName()); } - isAuthorized = rule.isAuthorized(runtimeParameter); - } catch(Exception e) { - //TODO figure out what which string goes where. - throw new AccessControlException("Access Denied", "An unhandled Exception was " + - "caught, so access is denied." + - "AccessControlException.", - e); - } - if(!isAuthorized) { - throw new AccessControlException("Access Denied", - "Access Denied for key: " + key + - " runtimeParameter: " + runtimeParameter); - } - } - + public void assertAuthorized(Object key, Object runtimeParameter) throws AccessControlException { + boolean isAuthorized; + try { + AccessControlRule rule = (AccessControlRule)ruleMap.get(key); + if(rule == null) { + throw new AccessControlException("Access Denied", + "AccessControlRule was not found for key: " + key); + } + if(logger.isDebugEnabled()){ logger.debug(Logger.EVENT_SUCCESS, "Asserting Authorization Rule \"" + key + "\" Using class: " + rule.getClass().getCanonicalName()); } + isAuthorized = rule.isAuthorized(runtimeParameter); + } catch(Exception e) { + //TODO figure out what which string goes where. + throw new AccessControlException("Access Denied", "An unhandled Exception was " + + "caught, so access is denied." + + "AccessControlException.", + e); + } + if(!isAuthorized) { + throw new AccessControlException("Access Denied", + "Access Denied for key: " + key + + " runtimeParameter: " + runtimeParameter); + } + } + /** {@inheritDoc} */ - public void assertAuthorizedForData(String action, Object data) - throws AccessControlException { - this.assertAuthorized("AC 1.0 Data", new Object[] {action, data}); - } + public void assertAuthorizedForData(String action, Object data) + throws AccessControlException { + this.assertAuthorized("AC 1.0 Data", new Object[] {action, data}); + } - /** + /** * {@inheritDoc} - * @deprecated - */ + * @deprecated + */ @Deprecated - public void assertAuthorizedForFile(String filepath) - throws AccessControlException { - this.assertAuthorized("AC 1.0 File", new Object[] {filepath}); - } + public void assertAuthorizedForFile(String filepath) + throws AccessControlException { + this.assertAuthorized("AC 1.0 File", new Object[] {filepath}); + } /** {@inheritDoc} */ - public void assertAuthorizedForFunction(String functionName) - throws AccessControlException { - this.assertAuthorized("AC 1.0 Function", new Object[] {functionName}); - } + public void assertAuthorizedForFunction(String functionName) + throws AccessControlException { + this.assertAuthorized("AC 1.0 Function", new Object[] {functionName}); + } /** {@inheritDoc} */ - public void assertAuthorizedForService(String serviceName) - throws AccessControlException { - this.assertAuthorized("AC 1.0 Service", new Object[] {serviceName}); - } + public void assertAuthorizedForService(String serviceName) + throws AccessControlException { + this.assertAuthorized("AC 1.0 Service", new Object[] {serviceName}); + } /** {@inheritDoc} */ - public void assertAuthorizedForURL(String url) - throws AccessControlException { - this.assertAuthorized("AC 1.0 URL", new Object[] {url}); - } + public void assertAuthorizedForURL(String url) + throws AccessControlException { + this.assertAuthorized("AC 1.0 URL", new Object[] {url}); + } /** {@inheritDoc} */ - public boolean isAuthorizedForData(String action, Object data) { - return this.isAuthorized("AC 1.0 Data", new Object[] {action, data}); - } + public boolean isAuthorizedForData(String action, Object data) { + return this.isAuthorized("AC 1.0 Data", new Object[] {action, data}); + } /** {@inheritDoc} */ - public boolean isAuthorizedForFile(String filepath) { - return this.isAuthorized("AC 1.0 File", new Object[] {filepath}); - } + public boolean isAuthorizedForFile(String filepath) { + return this.isAuthorized("AC 1.0 File", new Object[] {filepath}); + } /** {@inheritDoc} */ - public boolean isAuthorizedForFunction(String functionName) { - return this.isAuthorized("AC 1.0 Function", new Object[] {functionName}); - } + public boolean isAuthorizedForFunction(String functionName) { + return this.isAuthorized("AC 1.0 Function", new Object[] {functionName}); + } /** {@inheritDoc} */ - public boolean isAuthorizedForService(String serviceName) { - return this.isAuthorized("AC 1.0 Service", new Object[] {serviceName}); - } + public boolean isAuthorizedForService(String serviceName) { + return this.isAuthorized("AC 1.0 Service", new Object[] {serviceName}); + } /** {@inheritDoc} */ - public boolean isAuthorizedForURL(String url) { - return this.isAuthorized("AC 1.0 URL", new Object[] {url}); - } + public boolean isAuthorizedForURL(String url) { + return this.isAuthorized("AC 1.0 URL", new Object[] {url}); + } } diff --git a/src/main/java/org/owasp/esapi/reference/DefaultEncoder.java b/src/main/java/org/owasp/esapi/reference/DefaultEncoder.java index 5ecd5c0d1..49f8dac9b 100644 --- a/src/main/java/org/owasp/esapi/reference/DefaultEncoder.java +++ b/src/main/java/org/owasp/esapi/reference/DefaultEncoder.java @@ -71,84 +71,84 @@ public static Encoder getInstance() { return singletonInstance; } - // Codecs - private List codecs = new ArrayList(); - private HTMLEntityCodec htmlCodec = new HTMLEntityCodec(); - private XMLEntityCodec xmlCodec = new XMLEntityCodec(); - private PercentCodec percentCodec = new PercentCodec(); - private JavaScriptCodec javaScriptCodec = new JavaScriptCodec(); - private VBScriptCodec vbScriptCodec = new VBScriptCodec(); - private CSSCodec cssCodec = new CSSCodec(); + // Codecs + private List codecs = new ArrayList(); + private HTMLEntityCodec htmlCodec = new HTMLEntityCodec(); + private XMLEntityCodec xmlCodec = new XMLEntityCodec(); + private PercentCodec percentCodec = new PercentCodec(); + private JavaScriptCodec javaScriptCodec = new JavaScriptCodec(); + private VBScriptCodec vbScriptCodec = new VBScriptCodec(); + private CSSCodec cssCodec = new CSSCodec(); - private final Logger logger = ESAPI.getLogger("Encoder"); - - /** - * Character sets that define characters (in addition to alphanumerics) that are - * immune from encoding in various formats - */ - private final static char[] IMMUNE_HTML = { ',', '.', '-', '_', ' ' }; - private final static char[] IMMUNE_HTMLATTR = { ',', '.', '-', '_' }; - private final static char[] IMMUNE_CSS = { '#' }; - private final static char[] IMMUNE_JAVASCRIPT = { ',', '.', '_' }; - private final static char[] IMMUNE_VBSCRIPT = { ',', '.', '_' }; - private final static char[] IMMUNE_XML = { ',', '.', '-', '_', ' ' }; - private final static char[] IMMUNE_SQL = { ' ' }; - private final static char[] IMMUNE_OS = { '-' }; - private final static char[] IMMUNE_XMLATTR = { ',', '.', '-', '_' }; - private final static char[] IMMUNE_XPATH = { ',', '.', '-', '_', ' ' }; - - - /** - * Instantiates a new DefaultEncoder - */ - private DefaultEncoder() { - codecs.add( htmlCodec ); - codecs.add( percentCodec ); - codecs.add( javaScriptCodec ); - } - - public DefaultEncoder( List codecNames ) { - for ( String clazz : codecNames ) { - try { - if ( clazz.indexOf( '.' ) == -1 ) clazz = "org.owasp.esapi.codecs." + clazz; - codecs.add( Class.forName( clazz ).newInstance() ); - } catch ( Exception e ) { - logger.warning( Logger.EVENT_FAILURE, "Codec " + clazz + " listed in ESAPI.properties not on classpath" ); - } - } - } - - /** - * {@inheritDoc} - */ - public String canonicalize( String input ) { - if ( input == null ) { - return null; - } + private final Logger logger = ESAPI.getLogger("Encoder"); + + /** + * Character sets that define characters (in addition to alphanumerics) that are + * immune from encoding in various formats + */ + private final static char[] IMMUNE_HTML = { ',', '.', '-', '_', ' ' }; + private final static char[] IMMUNE_HTMLATTR = { ',', '.', '-', '_' }; + private final static char[] IMMUNE_CSS = { '#' }; + private final static char[] IMMUNE_JAVASCRIPT = { ',', '.', '_' }; + private final static char[] IMMUNE_VBSCRIPT = { ',', '.', '_' }; + private final static char[] IMMUNE_XML = { ',', '.', '-', '_', ' ' }; + private final static char[] IMMUNE_SQL = { ' ' }; + private final static char[] IMMUNE_OS = { '-' }; + private final static char[] IMMUNE_XMLATTR = { ',', '.', '-', '_' }; + private final static char[] IMMUNE_XPATH = { ',', '.', '-', '_', ' ' }; + + + /** + * Instantiates a new DefaultEncoder + */ + private DefaultEncoder() { + codecs.add( htmlCodec ); + codecs.add( percentCodec ); + codecs.add( javaScriptCodec ); + } + + public DefaultEncoder( List codecNames ) { + for ( String clazz : codecNames ) { + try { + if ( clazz.indexOf( '.' ) == -1 ) clazz = "org.owasp.esapi.codecs." + clazz; + codecs.add( Class.forName( clazz ).newInstance() ); + } catch ( Exception e ) { + logger.warning( Logger.EVENT_FAILURE, "Codec " + clazz + " listed in ESAPI.properties not on classpath" ); + } + } + } + + /** + * {@inheritDoc} + */ + public String canonicalize( String input ) { + if ( input == null ) { + return null; + } // Issue 231 - These are reverse boolean logic in the Encoder interface, so we need to invert these values - CS - return canonicalize(input, - !ESAPI.securityConfiguration().getAllowMultipleEncoding(), - !ESAPI.securityConfiguration().getAllowMixedEncoding() ); - } + return canonicalize(input, + !ESAPI.securityConfiguration().getAllowMultipleEncoding(), + !ESAPI.securityConfiguration().getAllowMixedEncoding() ); + } - - /** - * {@inheritDoc} - */ - public String canonicalize( String input, boolean strict) { - return canonicalize(input, strict, strict); - } + + /** + * {@inheritDoc} + */ + public String canonicalize( String input, boolean strict) { + return canonicalize(input, strict, strict); + } - /** - * {@inheritDoc} - */ - public String canonicalize( String input, boolean restrictMultiple, boolean restrictMixed ) { - if ( input == null ) { - return null; - } - + /** + * {@inheritDoc} + */ + public String canonicalize( String input, boolean restrictMultiple, boolean restrictMixed ) { + if ( input == null ) { + return null; + } + String working = input; Codec codecFound = null; int mixedCount = 1; @@ -199,418 +199,418 @@ else if ( mixedCount > 1 ) { } } return working; - } + } - /** - * {@inheritDoc} - */ - public String encodeForHTML(String input) { - if( input == null ) { - return null; - } - return htmlCodec.encode( IMMUNE_HTML, input); - } - - /** - * {@inheritDoc} - */ - public String decodeForHTML(String input) { - - if( input == null ) { - return null; - } - return htmlCodec.decode( input); + /** + * {@inheritDoc} + */ + public String encodeForHTML(String input) { + if( input == null ) { + return null; + } + return htmlCodec.encode( IMMUNE_HTML, input); + } + + /** + * {@inheritDoc} + */ + public String decodeForHTML(String input) { + + if( input == null ) { + return null; + } + return htmlCodec.decode( input); + } + + /** + * {@inheritDoc} + */ + public String encodeForHTMLAttribute(String input) { + if( input == null ) { + return null; + } + return htmlCodec.encode( IMMUNE_HTMLATTR, input); } - - /** - * {@inheritDoc} - */ - public String encodeForHTMLAttribute(String input) { - if( input == null ) { - return null; - } - return htmlCodec.encode( IMMUNE_HTMLATTR, input); - } - - /** - * {@inheritDoc} - */ - public String encodeForCSS(String input) { - if( input == null ) { - return null; - } - return cssCodec.encode( IMMUNE_CSS, input); - } + + /** + * {@inheritDoc} + */ + public String encodeForCSS(String input) { + if( input == null ) { + return null; + } + return cssCodec.encode( IMMUNE_CSS, input); + } - - /** - * {@inheritDoc} - */ - public String encodeForJavaScript(String input) { - if( input == null ) { - return null; - } - return javaScriptCodec.encode(IMMUNE_JAVASCRIPT, input); - } + + /** + * {@inheritDoc} + */ + public String encodeForJavaScript(String input) { + if( input == null ) { + return null; + } + return javaScriptCodec.encode(IMMUNE_JAVASCRIPT, input); + } - /** - * {@inheritDoc} - */ - public String encodeForVBScript(String input) { - if( input == null ) { - return null; - } - return vbScriptCodec.encode(IMMUNE_VBSCRIPT, input); - } + /** + * {@inheritDoc} + */ + public String encodeForVBScript(String input) { + if( input == null ) { + return null; + } + return vbScriptCodec.encode(IMMUNE_VBSCRIPT, input); + } - - /** - * {@inheritDoc} - */ - public String encodeForSQL(Codec codec, String input) { - if( input == null ) { - return null; - } - return codec.encode(IMMUNE_SQL, input); - } + + /** + * {@inheritDoc} + */ + public String encodeForSQL(Codec codec, String input) { + if( input == null ) { + return null; + } + return codec.encode(IMMUNE_SQL, input); + } - /** - * {@inheritDoc} - */ - public String encodeForOS(Codec codec, String input) { - if( input == null ) { - return null; - } - return codec.encode( IMMUNE_OS, input); - } + /** + * {@inheritDoc} + */ + public String encodeForOS(Codec codec, String input) { + if( input == null ) { + return null; + } + return codec.encode( IMMUNE_OS, input); + } - /** - * {@inheritDoc} - */ - public String encodeForLDAP(String input) { - return encodeForLDAP(input, true); - } - - /** - * {@inheritDoc} - */ - public String encodeForLDAP(String input, boolean encodeWildcards) { - if( input == null ) { - return null; - } - // TODO: replace with LDAP codec - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < input.length(); i++) { - char c = input.charAt(i); + /** + * {@inheritDoc} + */ + public String encodeForLDAP(String input) { + return encodeForLDAP(input, true); + } + + /** + * {@inheritDoc} + */ + public String encodeForLDAP(String input, boolean encodeWildcards) { + if( input == null ) { + return null; + } + // TODO: replace with LDAP codec + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < input.length(); i++) { + char c = input.charAt(i); - switch (c) { - case '\\': - sb.append("\\5c"); - break; - case '*': - if (encodeWildcards) { - sb.append("\\2a"); - } - else { - sb.append(c); - } - - break; - case '(': - sb.append("\\28"); - break; - case ')': - sb.append("\\29"); - break; - case '\0': - sb.append("\\00"); - break; - default: - sb.append(c); - } - } - return sb.toString(); - } + switch (c) { + case '\\': + sb.append("\\5c"); + break; + case '*': + if (encodeWildcards) { + sb.append("\\2a"); + } + else { + sb.append(c); + } + + break; + case '(': + sb.append("\\28"); + break; + case ')': + sb.append("\\29"); + break; + case '\0': + sb.append("\\00"); + break; + default: + sb.append(c); + } + } + return sb.toString(); + } - /** - * {@inheritDoc} - */ - public String encodeForDN(String input) { - if( input == null ) { - return null; - } - // TODO: replace with DN codec - StringBuilder sb = new StringBuilder(); - if ((input.length() > 0) && ((input.charAt(0) == ' ') || (input.charAt(0) == '#'))) { - sb.append('\\'); // add the leading backslash if needed - } - for (int i = 0; i < input.length(); i++) { - char c = input.charAt(i); - switch (c) { - case '\\': - sb.append("\\\\"); - break; - case ',': - sb.append("\\,"); - break; - case '+': - sb.append("\\+"); - break; - case '"': - sb.append("\\\""); - break; - case '<': - sb.append("\\<"); - break; - case '>': - sb.append("\\>"); - break; - case ';': - sb.append("\\;"); - break; - default: - sb.append(c); - } - } - // add the trailing backslash if needed - if ((input.length() > 1) && (input.charAt(input.length() - 1) == ' ')) { - sb.insert(sb.length() - 1, '\\'); - } - return sb.toString(); - } + /** + * {@inheritDoc} + */ + public String encodeForDN(String input) { + if( input == null ) { + return null; + } + // TODO: replace with DN codec + StringBuilder sb = new StringBuilder(); + if ((input.length() > 0) && ((input.charAt(0) == ' ') || (input.charAt(0) == '#'))) { + sb.append('\\'); // add the leading backslash if needed + } + for (int i = 0; i < input.length(); i++) { + char c = input.charAt(i); + switch (c) { + case '\\': + sb.append("\\\\"); + break; + case ',': + sb.append("\\,"); + break; + case '+': + sb.append("\\+"); + break; + case '"': + sb.append("\\\""); + break; + case '<': + sb.append("\\<"); + break; + case '>': + sb.append("\\>"); + break; + case ';': + sb.append("\\;"); + break; + default: + sb.append(c); + } + } + // add the trailing backslash if needed + if ((input.length() > 1) && (input.charAt(input.length() - 1) == ' ')) { + sb.insert(sb.length() - 1, '\\'); + } + return sb.toString(); + } - /** - * {@inheritDoc} - */ - public String encodeForXPath(String input) { - if( input == null ) { - return null; - } - return htmlCodec.encode( IMMUNE_XPATH, input); - } + /** + * {@inheritDoc} + */ + public String encodeForXPath(String input) { + if( input == null ) { + return null; + } + return htmlCodec.encode( IMMUNE_XPATH, input); + } - /** - * {@inheritDoc} - */ - public String encodeForXML(String input) { - if( input == null ) { - return null; - } - return xmlCodec.encode( IMMUNE_XML, input); - } + /** + * {@inheritDoc} + */ + public String encodeForXML(String input) { + if( input == null ) { + return null; + } + return xmlCodec.encode( IMMUNE_XML, input); + } - /** - * {@inheritDoc} - */ - public String encodeForXMLAttribute(String input) { - if( input == null ) { - return null; - } - return xmlCodec.encode( IMMUNE_XMLATTR, input); - } + /** + * {@inheritDoc} + */ + public String encodeForXMLAttribute(String input) { + if( input == null ) { + return null; + } + return xmlCodec.encode( IMMUNE_XMLATTR, input); + } - /** - * {@inheritDoc} - */ - public String encodeForURL(String input) throws EncodingException { - if ( input == null ) { - return null; - } - try { - return URLEncoder.encode(input, ESAPI.securityConfiguration().getCharacterEncoding()); - } catch (UnsupportedEncodingException ex) { - throw new EncodingException("Encoding failure", "Character encoding not supported", ex); - } catch (Exception e) { - throw new EncodingException("Encoding failure", "Problem URL encoding input", e); - } - } + /** + * {@inheritDoc} + */ + public String encodeForURL(String input) throws EncodingException { + if ( input == null ) { + return null; + } + try { + return URLEncoder.encode(input, ESAPI.securityConfiguration().getCharacterEncoding()); + } catch (UnsupportedEncodingException ex) { + throw new EncodingException("Encoding failure", "Character encoding not supported", ex); + } catch (Exception e) { + throw new EncodingException("Encoding failure", "Problem URL encoding input", e); + } + } - /** - * {@inheritDoc} - */ - public String decodeFromURL(String input) throws EncodingException { - if ( input == null ) { - return null; - } - String canonical = canonicalize(input); - try { - return URLDecoder.decode(canonical, ESAPI.securityConfiguration().getCharacterEncoding()); - } catch (UnsupportedEncodingException ex) { - throw new EncodingException("Decoding failed", "Character encoding not supported", ex); - } catch (Exception e) { - throw new EncodingException("Decoding failed", "Problem URL decoding input", e); - } - } + /** + * {@inheritDoc} + */ + public String decodeFromURL(String input) throws EncodingException { + if ( input == null ) { + return null; + } + String canonical = canonicalize(input); + try { + return URLDecoder.decode(canonical, ESAPI.securityConfiguration().getCharacterEncoding()); + } catch (UnsupportedEncodingException ex) { + throw new EncodingException("Decoding failed", "Character encoding not supported", ex); + } catch (Exception e) { + throw new EncodingException("Decoding failed", "Problem URL decoding input", e); + } + } - /** - * {@inheritDoc} - */ - public String encodeForBase64(byte[] input, boolean wrap) { - if ( input == null ) { - return null; - } - int options = 0; - if ( !wrap ) { - options |= Base64.DONT_BREAK_LINES; - } - return Base64.encodeBytes(input, options); - } + /** + * {@inheritDoc} + */ + public String encodeForBase64(byte[] input, boolean wrap) { + if ( input == null ) { + return null; + } + int options = 0; + if ( !wrap ) { + options |= Base64.DONT_BREAK_LINES; + } + return Base64.encodeBytes(input, options); + } - /** - * {@inheritDoc} - */ - public byte[] decodeFromBase64(String input) throws IOException { - if ( input == null ) { - return null; - } - return Base64.decode( input ); - } - - /** - * {@inheritDoc} - * - * This will extract each piece of a URI according to parse zone as specified in RFC-3986 section 3, - * and it will construct a canonicalized String representing a version of the URI that is safe to - * run regex against. - * - * @param dirtyUri - * @return Canonicalized URI string. - * @throws IntrusionException - */ - public String getCanonicalizedURI(URI dirtyUri) throws IntrusionException{ - -// From RFC-3986 section 3 -// URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] + /** + * {@inheritDoc} + */ + public byte[] decodeFromBase64(String input) throws IOException { + if ( input == null ) { + return null; + } + return Base64.decode( input ); + } + + /** + * {@inheritDoc} + * + * This will extract each piece of a URI according to parse zone as specified in RFC-3986 section 3, + * and it will construct a canonicalized String representing a version of the URI that is safe to + * run regex against. + * + * @param dirtyUri + * @return Canonicalized URI string. + * @throws IntrusionException + */ + public String getCanonicalizedURI(URI dirtyUri) throws IntrusionException{ + +// From RFC-3986 section 3 +// URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] // -// hier-part = "//" authority path-abempty -// / path-absolute -// / path-rootless -// / path-empty - -// The following are two example URIs and their component parts: +// hier-part = "//" authority path-abempty +// / path-absolute +// / path-rootless +// / path-empty + +// The following are two example URIs and their component parts: // -// foo://example.com:8042/over/there?name=ferret#nose -// \_/ \______________/\_________/ \_________/ \__/ -// | | | | | -// scheme authority path query fragment -// | _____________________|__ -// / \ / \ -// urn:example:animal:ferret:nose - Map parseMap = new EnumMap(UriSegment.class); - parseMap.put(UriSegment.SCHEME, dirtyUri.getScheme()); - //authority = [ userinfo "@" ] host [ ":" port ] - parseMap.put(UriSegment.AUTHORITY, dirtyUri.getRawAuthority()); - parseMap.put(UriSegment.SCHEMSPECIFICPART, dirtyUri.getRawSchemeSpecificPart()); - parseMap.put(UriSegment.HOST, dirtyUri.getHost()); - //if port is undefined, it will return -1 - Integer port = new Integer(dirtyUri.getPort()); - parseMap.put(UriSegment.PORT, port == -1 ? "": port.toString()); - parseMap.put(UriSegment.PATH, dirtyUri.getRawPath()); - parseMap.put(UriSegment.QUERY, dirtyUri.getRawQuery()); - parseMap.put(UriSegment.FRAGMENT, dirtyUri.getRawFragment()); - - //Now we canonicalize each part and build our string. - StringBuilder sb = new StringBuilder(); - - //Replace all the items in the map with canonicalized versions. - - Set set = parseMap.keySet(); - - SecurityConfiguration sg = ESAPI.securityConfiguration(); - boolean allowMixed = sg.getBooleanProp("Encoder.AllowMixedEncoding"); - boolean allowMultiple = sg.getBooleanProp("Encoder.AllowMultipleEncoding"); - for(UriSegment seg: set){ - String value = canonicalize(parseMap.get(seg), allowMultiple, allowMixed); - value = value == null ? "" : value; - //In the case of a uri query, we need to break up and canonicalize the internal parts of the query. - if(seg == UriSegment.QUERY && null != parseMap.get(seg)){ - StringBuilder qBuilder = new StringBuilder(); - try { - Map> canonicalizedMap = this.splitQuery(dirtyUri); - Set>> query = canonicalizedMap.entrySet(); - Iterator>> i = query.iterator(); - while(i.hasNext()){ - Entry> e = i.next(); - String key = e.getKey(); - String qVal = ""; - List list = e.getValue(); - if(!list.isEmpty()){ - qVal = list.get(0); - } - qBuilder.append(key) - .append("=") - .append(qVal); - - if(i.hasNext()){ - qBuilder.append("&"); - } - } - value = qBuilder.toString(); - } catch (UnsupportedEncodingException e) { - logger.debug(Logger.EVENT_FAILURE, "decoding error when parsing [" + dirtyUri.toString() + "]"); - } - } - //Check if the port is -1, if it is, omit it from the output. - if(seg == UriSegment.PORT){ - if("-1" == parseMap.get(seg)){ - value = ""; - } - } - parseMap.put(seg, value ); - } - - return buildUrl(parseMap); - } - - /** - * All the parts should be canonicalized by this point. This is straightforward assembly. - * - * @param parseMap The parts of the URL to put back together. - * @return The canonicalized URL. - */ - protected String buildUrl(Map parseMap){ - StringBuilder sb = new StringBuilder(); - sb.append(parseMap.get(UriSegment.SCHEME)) - .append("://") - //can't use SCHEMESPECIFICPART for this, because we need to canonicalize all the parts of the query. - //USERINFO is also deprecated. So we technically have more than we need. - .append(parseMap.get(UriSegment.AUTHORITY) == null || parseMap.get(UriSegment.AUTHORITY).equals("") ? "" : parseMap.get(UriSegment.AUTHORITY)) - .append(parseMap.get(UriSegment.PATH) == null || parseMap.get(UriSegment.PATH).equals("") ? "" : parseMap.get(UriSegment.PATH)) - .append(parseMap.get(UriSegment.QUERY) == null || parseMap.get(UriSegment.QUERY).equals("") - ? "" : "?" + parseMap.get(UriSegment.QUERY)) - .append((parseMap.get(UriSegment.FRAGMENT) == null) || parseMap.get(UriSegment.FRAGMENT).equals("") - ? "": "#" + parseMap.get(UriSegment.FRAGMENT)) - ; - return sb.toString(); - } - - public enum UriSegment { - AUTHORITY, SCHEME, SCHEMSPECIFICPART, USERINFO, HOST, PORT, PATH, QUERY, FRAGMENT - } - - - /** - * The meat of this method was taken from StackOverflow: http://stackoverflow.com/a/13592567/557153 - * It has been modified to return a canonicalized key and value pairing. - * - * @param uri The URI to analyze. - * @return a map of canonicalized query parameters. - * @throws UnsupportedEncodingException - */ - public Map> splitQuery(URI uri) throws UnsupportedEncodingException { - final Map> query_pairs = new LinkedHashMap>(); - final String[] pairs = uri.getQuery().split("&"); - for (String pair : pairs) { - final int idx = pair.indexOf("="); - final String key = idx > 0 ? canonicalize(pair.substring(0, idx)) : pair; - if (!query_pairs.containsKey(key)) { - query_pairs.put(key, new LinkedList()); - } - final String value = idx > 0 && pair.length() > idx + 1 ? URLDecoder.decode(pair.substring(idx + 1), "UTF-8") : null; - query_pairs.get(key).add(canonicalize(value)); - } - return query_pairs; - } +// foo://example.com:8042/over/there?name=ferret#nose +// \_/ \______________/\_________/ \_________/ \__/ +// | | | | | +// scheme authority path query fragment +// | _____________________|__ +// / \ / \ +// urn:example:animal:ferret:nose + Map parseMap = new EnumMap(UriSegment.class); + parseMap.put(UriSegment.SCHEME, dirtyUri.getScheme()); + //authority = [ userinfo "@" ] host [ ":" port ] + parseMap.put(UriSegment.AUTHORITY, dirtyUri.getRawAuthority()); + parseMap.put(UriSegment.SCHEMSPECIFICPART, dirtyUri.getRawSchemeSpecificPart()); + parseMap.put(UriSegment.HOST, dirtyUri.getHost()); + //if port is undefined, it will return -1 + Integer port = new Integer(dirtyUri.getPort()); + parseMap.put(UriSegment.PORT, port == -1 ? "": port.toString()); + parseMap.put(UriSegment.PATH, dirtyUri.getRawPath()); + parseMap.put(UriSegment.QUERY, dirtyUri.getRawQuery()); + parseMap.put(UriSegment.FRAGMENT, dirtyUri.getRawFragment()); + + //Now we canonicalize each part and build our string. + StringBuilder sb = new StringBuilder(); + + //Replace all the items in the map with canonicalized versions. + + Set set = parseMap.keySet(); + + SecurityConfiguration sg = ESAPI.securityConfiguration(); + boolean allowMixed = sg.getBooleanProp("Encoder.AllowMixedEncoding"); + boolean allowMultiple = sg.getBooleanProp("Encoder.AllowMultipleEncoding"); + for(UriSegment seg: set){ + String value = canonicalize(parseMap.get(seg), allowMultiple, allowMixed); + value = value == null ? "" : value; + //In the case of a uri query, we need to break up and canonicalize the internal parts of the query. + if(seg == UriSegment.QUERY && null != parseMap.get(seg)){ + StringBuilder qBuilder = new StringBuilder(); + try { + Map> canonicalizedMap = this.splitQuery(dirtyUri); + Set>> query = canonicalizedMap.entrySet(); + Iterator>> i = query.iterator(); + while(i.hasNext()){ + Entry> e = i.next(); + String key = e.getKey(); + String qVal = ""; + List list = e.getValue(); + if(!list.isEmpty()){ + qVal = list.get(0); + } + qBuilder.append(key) + .append("=") + .append(qVal); + + if(i.hasNext()){ + qBuilder.append("&"); + } + } + value = qBuilder.toString(); + } catch (UnsupportedEncodingException e) { + logger.debug(Logger.EVENT_FAILURE, "decoding error when parsing [" + dirtyUri.toString() + "]"); + } + } + //Check if the port is -1, if it is, omit it from the output. + if(seg == UriSegment.PORT){ + if("-1" == parseMap.get(seg)){ + value = ""; + } + } + parseMap.put(seg, value ); + } + + return buildUrl(parseMap); + } + + /** + * All the parts should be canonicalized by this point. This is straightforward assembly. + * + * @param parseMap The parts of the URL to put back together. + * @return The canonicalized URL. + */ + protected String buildUrl(Map parseMap){ + StringBuilder sb = new StringBuilder(); + sb.append(parseMap.get(UriSegment.SCHEME)) + .append("://") + //can't use SCHEMESPECIFICPART for this, because we need to canonicalize all the parts of the query. + //USERINFO is also deprecated. So we technically have more than we need. + .append(parseMap.get(UriSegment.AUTHORITY) == null || parseMap.get(UriSegment.AUTHORITY).equals("") ? "" : parseMap.get(UriSegment.AUTHORITY)) + .append(parseMap.get(UriSegment.PATH) == null || parseMap.get(UriSegment.PATH).equals("") ? "" : parseMap.get(UriSegment.PATH)) + .append(parseMap.get(UriSegment.QUERY) == null || parseMap.get(UriSegment.QUERY).equals("") + ? "" : "?" + parseMap.get(UriSegment.QUERY)) + .append((parseMap.get(UriSegment.FRAGMENT) == null) || parseMap.get(UriSegment.FRAGMENT).equals("") + ? "": "#" + parseMap.get(UriSegment.FRAGMENT)) + ; + return sb.toString(); + } + + public enum UriSegment { + AUTHORITY, SCHEME, SCHEMSPECIFICPART, USERINFO, HOST, PORT, PATH, QUERY, FRAGMENT + } + + + /** + * The meat of this method was taken from StackOverflow: http://stackoverflow.com/a/13592567/557153 + * It has been modified to return a canonicalized key and value pairing. + * + * @param uri The URI to analyze. + * @return a map of canonicalized query parameters. + * @throws UnsupportedEncodingException + */ + public Map> splitQuery(URI uri) throws UnsupportedEncodingException { + final Map> query_pairs = new LinkedHashMap>(); + final String[] pairs = uri.getQuery().split("&"); + for (String pair : pairs) { + final int idx = pair.indexOf("="); + final String key = idx > 0 ? canonicalize(pair.substring(0, idx)) : pair; + if (!query_pairs.containsKey(key)) { + query_pairs.put(key, new LinkedList()); + } + final String value = idx > 0 && pair.length() > idx + 1 ? URLDecoder.decode(pair.substring(idx + 1), "UTF-8") : null; + query_pairs.get(key).add(canonicalize(value)); + } + return query_pairs; + } } diff --git a/src/main/java/org/owasp/esapi/reference/DefaultExecutor.java b/src/main/java/org/owasp/esapi/reference/DefaultExecutor.java index eabb840cb..a086b247f 100644 --- a/src/main/java/org/owasp/esapi/reference/DefaultExecutor.java +++ b/src/main/java/org/owasp/esapi/reference/DefaultExecutor.java @@ -66,23 +66,23 @@ public static Executor getInstance() { * Instantiate a new Executor */ private DefaultExecutor() { - if ( System.getProperty("os.name").indexOf("Windows") != -1 ) { - logger.warning( Logger.SECURITY_SUCCESS, "Using WindowsCodec for Executor. If this is not running on Windows this could allow injection" ); - codec = new WindowsCodec(); - } else { - logger.warning( Logger.SECURITY_SUCCESS, "Using UnixCodec for Executor. If this is not running on Unix this could allow injection" ); - codec = new UnixCodec(); - } + if ( System.getProperty("os.name").indexOf("Windows") != -1 ) { + logger.warning( Logger.SECURITY_SUCCESS, "Using WindowsCodec for Executor. If this is not running on Windows this could allow injection" ); + codec = new WindowsCodec(); + } else { + logger.warning( Logger.SECURITY_SUCCESS, "Using UnixCodec for Executor. If this is not running on Unix this could allow injection" ); + codec = new UnixCodec(); + } } /** * {@inheritDoc} */ public ExecuteResult executeSystemCommand(File executable, List params) throws ExecutorException { - File workdir = ESAPI.securityConfiguration().getWorkingDirectory(); - boolean logParams = false; - boolean redirectErrorStream = false; - return executeSystemCommand( executable, params, workdir, codec, logParams, redirectErrorStream ); + File workdir = ESAPI.securityConfiguration().getWorkingDirectory(); + boolean logParams = false; + boolean redirectErrorStream = false; + return executeSystemCommand( executable, params, workdir, codec, logParams, redirectErrorStream ); } /** @@ -108,8 +108,8 @@ public ExecuteResult executeSystemCommand(File executable, List params, File wor // executable must use canonical path if ( !executable.getPath().equals( executable.getCanonicalPath() ) ) { - throw new ExecutorException("Execution failure", "Attempt to invoke an executable using a non-canonical path: " + executable); - } + throw new ExecutorException("Execution failure", "Attempt to invoke an executable using a non-canonical path: " + executable); + } // exact, absolute, canonical path to executable must be listed in ESAPI configuration List approved = ESAPI.securityConfiguration().getAllowedExecutables(); @@ -119,8 +119,8 @@ public ExecuteResult executeSystemCommand(File executable, List params, File wor // escape any special characters in the parameters for ( int i = 0; i < params.size(); i++ ) { - String param = (String)params.get(i); - params.set( i, ESAPI.encoder().encodeForOS(codec, param)); + String param = (String)params.get(i); + params.set( i, ESAPI.encoder().encodeForOS(codec, param)); } // working directory must exist @@ -143,9 +143,9 @@ public ExecuteResult executeSystemCommand(File executable, List params, File wor pb.redirectErrorStream(redirectErrorStream); if ( logParams ) { - logger.debug(Logger.SECURITY_SUCCESS, "Initiating executable: " + executable + " " + params + " in " + workdir); + logger.debug(Logger.SECURITY_SUCCESS, "Initiating executable: " + executable + " " + params + " in " + workdir); } else { - logger.debug(Logger.SECURITY_SUCCESS, "Initiating executable: " + executable + " [sensitive parameters obscured] in " + workdir); + logger.debug(Logger.SECURITY_SUCCESS, "Initiating executable: " + executable + " [sensitive parameters obscured] in " + workdir); } final StringBuilder outputBuffer = new StringBuilder(); @@ -154,37 +154,37 @@ public ExecuteResult executeSystemCommand(File executable, List params, File wor try { ReadThread errorReader; if (!redirectErrorStream) { - errorReader = new ReadThread(process.getErrorStream(), errorsBuffer); - errorReader.start(); + errorReader = new ReadThread(process.getErrorStream(), errorsBuffer); + errorReader.start(); } else { - errorReader = null; + errorReader = null; + } + readStream( process.getInputStream(), outputBuffer ); + if (errorReader != null) { + errorReader.join(); + if (errorReader.exception != null) { + throw errorReader.exception; + } } - readStream( process.getInputStream(), outputBuffer ); - if (errorReader != null) { - errorReader.join(); - if (errorReader.exception != null) { - throw errorReader.exception; - } - } - process.waitFor(); + process.waitFor(); } catch (Throwable e) { - process.destroy(); - throw new ExecutorException("Execution failure", "Exception thrown during execution of system command: " + e.getMessage(), e); + process.destroy(); + throw new ExecutorException("Execution failure", "Exception thrown during execution of system command: " + e.getMessage(), e); } String output = outputBuffer.toString(); String errors = errorsBuffer.toString(); int exitValue = process.exitValue(); if ( errors != null && errors.length() > 0 ) { - String logErrors = errors; - final int MAX_LEN = 256; - if (logErrors.length() > MAX_LEN) { - logErrors = logErrors.substring(0, MAX_LEN) + "(truncated at "+MAX_LEN+" characters)"; - } - logger.warning( Logger.SECURITY_SUCCESS, "Error during system command: " + logErrors ); + String logErrors = errors; + final int MAX_LEN = 256; + if (logErrors.length() > MAX_LEN) { + logErrors = logErrors.substring(0, MAX_LEN) + "(truncated at "+MAX_LEN+" characters)"; + } + logger.warning( Logger.SECURITY_SUCCESS, "Error during system command: " + logErrors ); } if ( exitValue != 0 ) { - logger.warning( Logger.EVENT_FAILURE, "System command exited with non-zero status: " + exitValue ); + logger.warning( Logger.EVENT_FAILURE, "System command exited with non-zero status: " + exitValue ); } logger.debug(Logger.SECURITY_SUCCESS, "System command complete"); @@ -198,36 +198,36 @@ public ExecuteResult executeSystemCommand(File executable, List params, File wor * readStream reads lines from an input stream and returns all of them in a single string * * @param is - * input stream to read from + * input stream to read from * @throws IOException */ private static void readStream( InputStream is, StringBuilder sb ) throws IOException { - InputStreamReader isr = new InputStreamReader(is); - BufferedReader br = new BufferedReader(isr); - String line; - while ((line = br.readLine()) != null) { - sb.append(line).append('\n'); - } + InputStreamReader isr = new InputStreamReader(is); + BufferedReader br = new BufferedReader(isr); + String line; + while ((line = br.readLine()) != null) { + sb.append(line).append('\n'); + } } private static class ReadThread extends Thread { - volatile IOException exception; - private final InputStream stream; - private final StringBuilder buffer; - - ReadThread(InputStream stream, StringBuilder buffer) { - this.stream = stream; - this.buffer = buffer; - } - - @Override - public void run() { - try { - readStream(stream, buffer); - } catch (IOException e) { - exception = e; - } - } + volatile IOException exception; + private final InputStream stream; + private final StringBuilder buffer; + + ReadThread(InputStream stream, StringBuilder buffer) { + this.stream = stream; + this.buffer = buffer; + } + + @Override + public void run() { + try { + readStream(stream, buffer); + } catch (IOException e) { + exception = e; + } + } } diff --git a/src/main/java/org/owasp/esapi/reference/DefaultHTTPUtilities.java b/src/main/java/org/owasp/esapi/reference/DefaultHTTPUtilities.java index a9212f2c6..9bd2a98f4 100644 --- a/src/main/java/org/owasp/esapi/reference/DefaultHTTPUtilities.java +++ b/src/main/java/org/owasp/esapi/reference/DefaultHTTPUtilities.java @@ -97,7 +97,7 @@ public static HTTPUtilities getInstance() { return instance; } - /** + /** * Defines the ThreadLocalRequest to store the current request for this thread. */ private class ThreadLocalRequest extends InheritableThreadLocal { @@ -107,7 +107,7 @@ public HttpServletRequest getRequest() { } public HttpServletRequest initialValue() { - return null; + return null; } public void setRequest(HttpServletRequest newRequest) { @@ -115,7 +115,7 @@ public void setRequest(HttpServletRequest newRequest) { } } - /** + /** * Defines the ThreadLocalResponse to store the current response for this thread. */ private class ThreadLocalResponse extends InheritableThreadLocal { @@ -125,7 +125,7 @@ public HttpServletResponse getResponse() { } public HttpServletResponse initialValue() { - return null; + return null; } public void setResponse(HttpServletResponse newResponse) { @@ -134,10 +134,10 @@ public void setResponse(HttpServletResponse newResponse) { } /** The logger. */ - private final Logger logger = ESAPI.getLogger("HTTPUtilities"); + private final Logger logger = ESAPI.getLogger("HTTPUtilities"); /** The max bytes. */ - static final int maxBytes = ESAPI.securityConfiguration().getAllowedFileUploadSize(); + static final int maxBytes = ESAPI.securityConfiguration().getAllowedFileUploadSize(); /* @@ -147,7 +147,7 @@ public void setResponse(HttpServletResponse newResponse) { */ private ThreadLocalRequest currentRequest = new ThreadLocalRequest(); - /* + /* * The currentResponse ThreadLocal variable is used to make the currentResponse available to any call in any part of an * application. This enables API's for actions that require the response to be much simpler. For example, the logout() * method in the Authenticator class requires the currentResponse to kill the Session ID cookie. @@ -156,29 +156,29 @@ public void setResponse(HttpServletResponse newResponse) { - /** + /** * No arg constructor. */ public DefaultHTTPUtilities() { - } + } - /** - * {@inheritDoc} + /** + * {@inheritDoc} * This implementation uses a custom "set-cookie" header rather than Java's * cookie interface which doesn't allow the use of HttpOnly. Configure the * HttpOnly and Secure settings in ESAPI.properties. - */ - public void addCookie( Cookie cookie ) { - addCookie( getCurrentResponse(), cookie ); + */ + public void addCookie( Cookie cookie ) { + addCookie( getCurrentResponse(), cookie ); } /** - * {@inheritDoc} + * {@inheritDoc} * This implementation uses a custom "set-cookie" header rather than Java's * cookie interface which doesn't allow the use of HttpOnly. Configure the * HttpOnly and Secure settings in ESAPI.properties. - */ + */ public void addCookie(HttpServletResponse response, Cookie cookie) { String name = cookie.getName(); String value = cookie.getValue(); @@ -195,14 +195,14 @@ public void addCookie(HttpServletResponse response, Cookie cookie) { // if there are no errors, then set the cookie either with a header or normally if (errors.size() == 0) { - if ( ESAPI.securityConfiguration().getForceHttpOnlyCookies() ) { - String header = createCookieHeader(cookieName, cookieValue, maxAge, domain, path, secure); - addHeader(response, "Set-Cookie", header); - } else { + if ( ESAPI.securityConfiguration().getForceHttpOnlyCookies() ) { + String header = createCookieHeader(cookieName, cookieValue, maxAge, domain, path, secure); + addHeader(response, "Set-Cookie", header); + } else { // Issue 23 - If the ESAPI Configuration is set to force secure cookies, force the secure flag on the cookie before setting it cookie.setSecure( secure || ESAPI.securityConfiguration().getForceSecureCookies() ); - response.addCookie(cookie); - } + response.addCookie(cookie); + } return; } logger.warning(Logger.SECURITY_FAILURE, "Attempt to add unsafe data to cookie (skip mode). Skipping cookie and continuing."); @@ -210,32 +210,32 @@ public void addCookie(HttpServletResponse response, Cookie cookie) { - /** - * {@inheritDoc} - */ - public String addCSRFToken(String href) { - User user = ESAPI.authenticator().getCurrentUser(); - if (user.isAnonymous()) { - return href; - } + /** + * {@inheritDoc} + */ + public String addCSRFToken(String href) { + User user = ESAPI.authenticator().getCurrentUser(); + if (user.isAnonymous()) { + return href; + } - // if there are already parameters append with &, otherwise append with ? - String token = CSRF_TOKEN_NAME + "=" + user.getCSRFToken(); - return href.indexOf( '?') != -1 ? href + "&" + token : href + "?" + token; - } + // if there are already parameters append with &, otherwise append with ? + String token = CSRF_TOKEN_NAME + "=" + user.getCSRFToken(); + return href.indexOf( '?') != -1 ? href + "&" + token : href + "?" + token; + } /** - * {@inheritDoc} + * {@inheritDoc} */ public void addHeader(String name, String value) { - addHeader( getCurrentResponse(), name, value ); + addHeader( getCurrentResponse(), name, value ); } /** - * {@inheritDoc} + * {@inheritDoc} */ public void addHeader(HttpServletResponse response, String name, String value) { - SecurityConfiguration sc = ESAPI.securityConfiguration(); + SecurityConfiguration sc = ESAPI.securityConfiguration(); try { String strippedName = StringUtilities.replaceLinearWhiteSpace(name); String strippedValue = StringUtilities.replaceLinearWhiteSpace(value); @@ -247,109 +247,109 @@ public void addHeader(HttpServletResponse response, String name, String value) { } } - /** - * {@inheritDoc} - */ - public void assertSecureChannel() throws AccessControlException { - assertSecureChannel( getCurrentRequest() ); - } - - /** - * {@inheritDoc} - * - * This implementation ignores the built-in isSecure() method - * and uses the URL to determine if the request was transmitted over SSL. - * This is because SSL may have been terminated somewhere outside the - * container. - */ - public void assertSecureChannel(HttpServletRequest request) throws AccessControlException { - if ( request == null ) { - throw new AccessControlException( "Insecure request received", "HTTP request was null" ); - } - StringBuffer sb = request.getRequestURL(); - if ( sb == null ) { - throw new AccessControlException( "Insecure request received", "HTTP request URL was null" ); - } - String url = sb.toString(); - if ( !url.startsWith( "https" ) ) { - throw new AccessControlException( "Insecure request received", "HTTP request did not use SSL" ); - } - } - - /** - * {@inheritDoc} - */ - public void assertSecureRequest() throws AccessControlException { - assertSecureRequest( getCurrentRequest() ); - } - - /** - * {@inheritDoc} - */ - public void assertSecureRequest(HttpServletRequest request) throws AccessControlException { - assertSecureChannel( request ); - String receivedMethod = request.getMethod(); - String requiredMethod = "POST"; - if ( !receivedMethod.equals( requiredMethod ) ) { - throw new AccessControlException( "Insecure request received", "Received request using " + receivedMethod + " when only " + requiredMethod + " is allowed" ); - } - } - - /** - * {@inheritDoc} - */ - public HttpSession changeSessionIdentifier() throws AuthenticationException { - return changeSessionIdentifier( getCurrentRequest() ); - } - - /** - * {@inheritDoc} - */ - public HttpSession changeSessionIdentifier(HttpServletRequest request) throws AuthenticationException { - - // get the current session - HttpSession oldSession = request.getSession(); - - // make a copy of the session content - Map temp = new ConcurrentHashMap(); - Enumeration e = oldSession.getAttributeNames(); - while (e != null && e.hasMoreElements()) { - String name = (String) e.nextElement(); - Object value = oldSession.getAttribute(name); - temp.put(name, value); - } - - // kill the old session and create a new one - oldSession.invalidate(); - HttpSession newSession = request.getSession(); - User user = ESAPI.authenticator().getCurrentUser(); - user.addSession( newSession ); - user.removeSession( oldSession ); - - // copy back the session content + /** + * {@inheritDoc} + */ + public void assertSecureChannel() throws AccessControlException { + assertSecureChannel( getCurrentRequest() ); + } + + /** + * {@inheritDoc} + * + * This implementation ignores the built-in isSecure() method + * and uses the URL to determine if the request was transmitted over SSL. + * This is because SSL may have been terminated somewhere outside the + * container. + */ + public void assertSecureChannel(HttpServletRequest request) throws AccessControlException { + if ( request == null ) { + throw new AccessControlException( "Insecure request received", "HTTP request was null" ); + } + StringBuffer sb = request.getRequestURL(); + if ( sb == null ) { + throw new AccessControlException( "Insecure request received", "HTTP request URL was null" ); + } + String url = sb.toString(); + if ( !url.startsWith( "https" ) ) { + throw new AccessControlException( "Insecure request received", "HTTP request did not use SSL" ); + } + } + + /** + * {@inheritDoc} + */ + public void assertSecureRequest() throws AccessControlException { + assertSecureRequest( getCurrentRequest() ); + } + + /** + * {@inheritDoc} + */ + public void assertSecureRequest(HttpServletRequest request) throws AccessControlException { + assertSecureChannel( request ); + String receivedMethod = request.getMethod(); + String requiredMethod = "POST"; + if ( !receivedMethod.equals( requiredMethod ) ) { + throw new AccessControlException( "Insecure request received", "Received request using " + receivedMethod + " when only " + requiredMethod + " is allowed" ); + } + } + + /** + * {@inheritDoc} + */ + public HttpSession changeSessionIdentifier() throws AuthenticationException { + return changeSessionIdentifier( getCurrentRequest() ); + } + + /** + * {@inheritDoc} + */ + public HttpSession changeSessionIdentifier(HttpServletRequest request) throws AuthenticationException { + + // get the current session + HttpSession oldSession = request.getSession(); + + // make a copy of the session content + Map temp = new ConcurrentHashMap(); + Enumeration e = oldSession.getAttributeNames(); + while (e != null && e.hasMoreElements()) { + String name = (String) e.nextElement(); + Object value = oldSession.getAttribute(name); + temp.put(name, value); + } + + // kill the old session and create a new one + oldSession.invalidate(); + HttpSession newSession = request.getSession(); + User user = ESAPI.authenticator().getCurrentUser(); + user.addSession( newSession ); + user.removeSession( oldSession ); + + // copy back the session content for (Map.Entry stringObjectEntry : temp.entrySet()) { newSession.setAttribute(stringObjectEntry.getKey(), stringObjectEntry.getValue()); - } - return newSession; - } + } + return newSession; + } - /** - * {@inheritDoc} - */ + /** + * {@inheritDoc} + */ public void clearCurrent() { - currentRequest.set(null); - currentResponse.set(null); - } + currentRequest.set(null); + currentResponse.set(null); + } - private String createCookieHeader(String name, String value, int maxAge, String domain, String path, boolean secure) { + private String createCookieHeader(String name, String value, int maxAge, String domain, String path, boolean secure) { // create the special cookie header instead of creating a Java cookie // Set-Cookie:=[; =][; expires=][; // domain=][; path=][; secure][;HttpOnly] String header = name + "=" + value; - if (maxAge >= 0) { - header += "; Max-Age=" + maxAge; - } + if (maxAge >= 0) { + header += "; Max-Age=" + maxAge; + } if (domain != null) { header += "; Domain=" + domain; } @@ -365,486 +365,486 @@ private String createCookieHeader(String name, String value, int maxAge, String return header; } - /** - * {@inheritDoc} - */ - public String decryptHiddenField(String encrypted) { - try { - return decryptString(encrypted); - } catch( EncryptionException e ) { - throw new IntrusionException("Invalid request","Tampering detected. Hidden field data did not decrypt properly.", e); - } + /** + * {@inheritDoc} + */ + public String decryptHiddenField(String encrypted) { + try { + return decryptString(encrypted); + } catch( EncryptionException e ) { + throw new IntrusionException("Invalid request","Tampering detected. Hidden field data did not decrypt properly.", e); + } } - /** - * {@inheritDoc} - */ - public Map decryptQueryString(String encrypted) throws EncryptionException { + /** + * {@inheritDoc} + */ + public Map decryptQueryString(String encrypted) throws EncryptionException { String plaintext = decryptString(encrypted); - return queryToMap(plaintext); - } + return queryToMap(plaintext); + } - /** - * {@inheritDoc} - */ - public Map decryptStateFromCookie() throws EncryptionException { - return decryptStateFromCookie( getCurrentRequest() ); + /** + * {@inheritDoc} + */ + public Map decryptStateFromCookie() throws EncryptionException { + return decryptStateFromCookie( getCurrentRequest() ); } - /** - * {@inheritDoc} + /** + * {@inheritDoc} * * @param request */ public Map decryptStateFromCookie(HttpServletRequest request) throws EncryptionException { - try { - String encrypted = getCookie( request, ESAPI_STATE ); - if ( encrypted == null ) return new HashMap(); - String plaintext = decryptString(encrypted); - return queryToMap( plaintext ); - } catch( ValidationException e ) { - return null; - } - } - - /** - * {@inheritDoc} - */ - public String encryptHiddenField(String value) throws EncryptionException { - return encryptString(value); - } - - /** - * {@inheritDoc} - */ - public String encryptQueryString(String query) throws EncryptionException { - return encryptString(query); - } - - /** - * {@inheritDoc} + try { + String encrypted = getCookie( request, ESAPI_STATE ); + if ( encrypted == null ) return new HashMap(); + String plaintext = decryptString(encrypted); + return queryToMap( plaintext ); + } catch( ValidationException e ) { + return null; + } + } + + /** + * {@inheritDoc} + */ + public String encryptHiddenField(String value) throws EncryptionException { + return encryptString(value); + } + + /** + * {@inheritDoc} + */ + public String encryptQueryString(String query) throws EncryptionException { + return encryptString(query); + } + + /** + * {@inheritDoc} */ public void encryptStateInCookie(HttpServletResponse response, Map cleartext) throws EncryptionException { - StringBuilder sb = new StringBuilder(); - Iterator i = cleartext.entrySet().iterator(); - while ( i.hasNext() ) { - try { - Map.Entry entry = (Map.Entry)i.next(); - - // What do these need to be URL encoded? They are encrypted! - String name = ESAPI.encoder().encodeForURL( entry.getKey().toString() ); - String value = ESAPI.encoder().encodeForURL( entry.getValue().toString() ); + StringBuilder sb = new StringBuilder(); + Iterator i = cleartext.entrySet().iterator(); + while ( i.hasNext() ) { + try { + Map.Entry entry = (Map.Entry)i.next(); + + // What do these need to be URL encoded? They are encrypted! + String name = ESAPI.encoder().encodeForURL( entry.getKey().toString() ); + String value = ESAPI.encoder().encodeForURL( entry.getValue().toString() ); sb.append(name).append("=").append(value); - if ( i.hasNext() ) sb.append( "&" ); - } catch( EncodingException e ) { - logger.error(Logger.SECURITY_FAILURE, "Problem encrypting state in cookie - skipping entry", e ); - } - } + if ( i.hasNext() ) sb.append( "&" ); + } catch( EncodingException e ) { + logger.error(Logger.SECURITY_FAILURE, "Problem encrypting state in cookie - skipping entry", e ); + } + } - String encrypted = encryptString(sb.toString()); + String encrypted = encryptString(sb.toString()); - if ( encrypted.length() > (MAX_COOKIE_LEN ) ) { - logger.error(Logger.SECURITY_FAILURE, "Problem encrypting state in cookie - skipping entry"); - throw new EncryptionException("Encryption failure", "Encrypted cookie state of " + encrypted.length() + " longer than allowed " + MAX_COOKIE_LEN ); - } + if ( encrypted.length() > (MAX_COOKIE_LEN ) ) { + logger.error(Logger.SECURITY_FAILURE, "Problem encrypting state in cookie - skipping entry"); + throw new EncryptionException("Encryption failure", "Encrypted cookie state of " + encrypted.length() + " longer than allowed " + MAX_COOKIE_LEN ); + } - Cookie cookie = new Cookie( ESAPI_STATE, encrypted ); - addCookie( response, cookie ); + Cookie cookie = new Cookie( ESAPI_STATE, encrypted ); + addCookie( response, cookie ); } - /** - * {@inheritDoc} - */ - public void encryptStateInCookie( Map cleartext ) throws EncryptionException { - encryptStateInCookie( getCurrentResponse(), cleartext ); + /** + * {@inheritDoc} + */ + public void encryptStateInCookie( Map cleartext ) throws EncryptionException { + encryptStateInCookie( getCurrentResponse(), cleartext ); } - /** - * {@inheritDoc} - */ - public String getCookie( HttpServletRequest request, String name ) throws ValidationException { + /** + * {@inheritDoc} + */ + public String getCookie( HttpServletRequest request, String name ) throws ValidationException { Cookie c = getFirstCookie( request, name ); SecurityConfiguration sc = ESAPI.securityConfiguration(); if ( c == null ) return null; - String value = c.getValue(); - return ESAPI.validator().getValidInput("HTTP cookie value: " + value, value, "HTTPCookieValue", sc.getIntProp("HttpUtilities.MaxHeaderValueSize"), false); - } + String value = c.getValue(); + return ESAPI.validator().getValidInput("HTTP cookie value: " + value, value, "HTTPCookieValue", sc.getIntProp("HttpUtilities.MaxHeaderValueSize"), false); + } - /** - * {@inheritDoc} - */ + /** + * {@inheritDoc} + */ public String getCookie( String name ) throws ValidationException { - return getCookie( getCurrentRequest(), name ); + return getCookie( getCurrentRequest(), name ); } - /** - * {@inheritDoc} - */ - public String getCSRFToken() { - User user = ESAPI.authenticator().getCurrentUser(); - if (user == null) return null; - return user.getCSRFToken(); - } + /** + * {@inheritDoc} + */ + public String getCSRFToken() { + User user = ESAPI.authenticator().getCurrentUser(); + if (user == null) return null; + return user.getCSRFToken(); + } - /** - * {@inheritDoc} - */ + /** + * {@inheritDoc} + */ public HttpServletRequest getCurrentRequest() { - return currentRequest.getRequest(); + return currentRequest.getRequest(); } - /** - * {@inheritDoc} - */ + /** + * {@inheritDoc} + */ public HttpServletResponse getCurrentResponse() { return currentResponse.getResponse(); } - /** - * {@inheritDoc} - */ + /** + * {@inheritDoc} + */ public List getFileUploads() throws ValidationException { - return getFileUploads( getCurrentRequest(), ESAPI.securityConfiguration().getUploadDirectory(), ESAPI.securityConfiguration().getAllowedFileExtensions() ); + return getFileUploads( getCurrentRequest(), ESAPI.securityConfiguration().getUploadDirectory(), ESAPI.securityConfiguration().getAllowedFileExtensions() ); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public List getFileUploads(HttpServletRequest request) throws ValidationException { - return getFileUploads(request, ESAPI.securityConfiguration().getUploadDirectory(), ESAPI.securityConfiguration().getAllowedFileExtensions()); + return getFileUploads(request, ESAPI.securityConfiguration().getUploadDirectory(), ESAPI.securityConfiguration().getAllowedFileExtensions()); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public List getFileUploads(HttpServletRequest request, File finalDir ) throws ValidationException { - return getFileUploads(request, finalDir, ESAPI.securityConfiguration().getAllowedFileExtensions()); + return getFileUploads(request, finalDir, ESAPI.securityConfiguration().getAllowedFileExtensions()); } - /** - * {@inheritDoc} - */ - public List getFileUploads(HttpServletRequest request, File finalDir, List allowedExtensions) throws ValidationException { + /** + * {@inheritDoc} + */ + public List getFileUploads(HttpServletRequest request, File finalDir, List allowedExtensions) throws ValidationException { File tempDir = ESAPI.securityConfiguration().getUploadTempDirectory(); - if ( !tempDir.exists() ) { - if ( !tempDir.mkdirs() ) throw new ValidationUploadException( "Upload failed", "Could not create temp directory: " + tempDir.getAbsolutePath() ); - } - - if( finalDir != null){ - if ( !finalDir.exists() ) { - if ( !finalDir.mkdirs() ) throw new ValidationUploadException( "Upload failed", "Could not create final upload directory: " + finalDir.getAbsolutePath() ); - } - } - else { - if ( !ESAPI.securityConfiguration().getUploadDirectory().exists()) { - if ( !ESAPI.securityConfiguration().getUploadDirectory().mkdirs() ) throw new ValidationUploadException( "Upload failed", "Could not create final upload directory: " + ESAPI.securityConfiguration().getUploadDirectory().getAbsolutePath() ); - } - finalDir = ESAPI.securityConfiguration().getUploadDirectory(); - } - - List newFiles = new ArrayList(); - String dfiPrevValue = "false"; // Fail safely in case of Java Security Manager & weird security policy - try { - dfiPrevValue = System.getProperty(DISKFILEITEM_SERIALIZABLE); - System.setProperty(DISKFILEITEM_SERIALIZABLE, "false"); - final HttpSession session = request.getSession(false); - if (!ServletFileUpload.isMultipartContent(request)) { - throw new ValidationUploadException("Upload failed", "Not a multipart request"); - } - - // this factory will store ALL files in the temp directory, - // regardless of size - DiskFileItemFactory factory = new DiskFileItemFactory(0, tempDir); - ServletFileUpload upload = new ServletFileUpload(factory); - upload.setSizeMax(maxBytes); - - // Create a progress listener - ProgressListener progressListener = new ProgressListener() { - private long megaBytes = -1; - private long progress = 0; - - public void update(long pBytesRead, long pContentLength, int pItems) { - if (pItems == 0) - return; - long mBytes = pBytesRead / 1000000; - if (megaBytes == mBytes) - return; - megaBytes = mBytes; - progress = (long) (((double) pBytesRead / (double) pContentLength) * 100); - if ( session != null ) { - session.setAttribute("progress", Long.toString(progress)); - } - // logger.logSuccess(Logger.SECURITY, " Item " + pItems + " (" + progress + "% of " + pContentLength + " bytes]"); - } - }; - upload.setProgressListener(progressListener); - - List items = upload.parseRequest(request); - for (FileItem item : items) - { - if (!item.isFormField() && item.getName() != null && !(item.getName().equals(""))) - { - String[] fparts = item.getName().split("[\\/\\\\]"); - String filename = fparts[fparts.length - 1]; - - if (!ESAPI.validator().isValidFileName("upload", filename, allowedExtensions, false)) - { - throw new ValidationUploadException("Upload only simple filenames with the following extensions " + allowedExtensions, "Upload failed isValidFileName check"); - } - - logger.info(Logger.SECURITY_SUCCESS, "File upload requested: " + filename); - File f = new File(finalDir, filename); - if (f.exists()) - { - String[] parts = filename.split("\\/."); - String extension = ""; - if (parts.length > 1) - { - extension = parts[parts.length - 1]; - } - String filenm = filename.substring(0, filename.length() - extension.length()); - f = File.createTempFile(filenm, "." + extension, finalDir); - } - - item.write(f); - newFiles.add(f); - // delete temporary file - item.delete(); - logger.fatal(Logger.SECURITY_SUCCESS, "File successfully uploaded: " + f); - if (session != null) - { - session.setAttribute("progress", Long.toString(0)); - } - } - } - } catch (Exception e) { - if (e instanceof ValidationUploadException) { - throw (ValidationException)e; - } - throw new ValidationUploadException("Upload failure", "Problem during upload:" + e.getMessage(), e); - } - finally { - if ( dfiPrevValue != null ) { - System.setProperty(DISKFILEITEM_SERIALIZABLE, dfiPrevValue); - } - } - return Collections.synchronizedList(newFiles); - } - - - - /** + if ( !tempDir.exists() ) { + if ( !tempDir.mkdirs() ) throw new ValidationUploadException( "Upload failed", "Could not create temp directory: " + tempDir.getAbsolutePath() ); + } + + if( finalDir != null){ + if ( !finalDir.exists() ) { + if ( !finalDir.mkdirs() ) throw new ValidationUploadException( "Upload failed", "Could not create final upload directory: " + finalDir.getAbsolutePath() ); + } + } + else { + if ( !ESAPI.securityConfiguration().getUploadDirectory().exists()) { + if ( !ESAPI.securityConfiguration().getUploadDirectory().mkdirs() ) throw new ValidationUploadException( "Upload failed", "Could not create final upload directory: " + ESAPI.securityConfiguration().getUploadDirectory().getAbsolutePath() ); + } + finalDir = ESAPI.securityConfiguration().getUploadDirectory(); + } + + List newFiles = new ArrayList(); + String dfiPrevValue = "false"; // Fail safely in case of Java Security Manager & weird security policy + try { + dfiPrevValue = System.getProperty(DISKFILEITEM_SERIALIZABLE); + System.setProperty(DISKFILEITEM_SERIALIZABLE, "false"); + final HttpSession session = request.getSession(false); + if (!ServletFileUpload.isMultipartContent(request)) { + throw new ValidationUploadException("Upload failed", "Not a multipart request"); + } + + // this factory will store ALL files in the temp directory, + // regardless of size + DiskFileItemFactory factory = new DiskFileItemFactory(0, tempDir); + ServletFileUpload upload = new ServletFileUpload(factory); + upload.setSizeMax(maxBytes); + + // Create a progress listener + ProgressListener progressListener = new ProgressListener() { + private long megaBytes = -1; + private long progress = 0; + + public void update(long pBytesRead, long pContentLength, int pItems) { + if (pItems == 0) + return; + long mBytes = pBytesRead / 1000000; + if (megaBytes == mBytes) + return; + megaBytes = mBytes; + progress = (long) (((double) pBytesRead / (double) pContentLength) * 100); + if ( session != null ) { + session.setAttribute("progress", Long.toString(progress)); + } + // logger.logSuccess(Logger.SECURITY, " Item " + pItems + " (" + progress + "% of " + pContentLength + " bytes]"); + } + }; + upload.setProgressListener(progressListener); + + List items = upload.parseRequest(request); + for (FileItem item : items) + { + if (!item.isFormField() && item.getName() != null && !(item.getName().equals(""))) + { + String[] fparts = item.getName().split("[\\/\\\\]"); + String filename = fparts[fparts.length - 1]; + + if (!ESAPI.validator().isValidFileName("upload", filename, allowedExtensions, false)) + { + throw new ValidationUploadException("Upload only simple filenames with the following extensions " + allowedExtensions, "Upload failed isValidFileName check"); + } + + logger.info(Logger.SECURITY_SUCCESS, "File upload requested: " + filename); + File f = new File(finalDir, filename); + if (f.exists()) + { + String[] parts = filename.split("\\/."); + String extension = ""; + if (parts.length > 1) + { + extension = parts[parts.length - 1]; + } + String filenm = filename.substring(0, filename.length() - extension.length()); + f = File.createTempFile(filenm, "." + extension, finalDir); + } + + item.write(f); + newFiles.add(f); + // delete temporary file + item.delete(); + logger.fatal(Logger.SECURITY_SUCCESS, "File successfully uploaded: " + f); + if (session != null) + { + session.setAttribute("progress", Long.toString(0)); + } + } + } + } catch (Exception e) { + if (e instanceof ValidationUploadException) { + throw (ValidationException)e; + } + throw new ValidationUploadException("Upload failure", "Problem during upload:" + e.getMessage(), e); + } + finally { + if ( dfiPrevValue != null ) { + System.setProperty(DISKFILEITEM_SERIALIZABLE, dfiPrevValue); + } + } + return Collections.synchronizedList(newFiles); + } + + + + /** * Utility to return the first cookie matching the provided name. * @param request * @param name */ - private Cookie getFirstCookie(HttpServletRequest request, String name) { - Cookie[] cookies = request.getCookies(); - if (cookies != null) { + private Cookie getFirstCookie(HttpServletRequest request, String name) { + Cookie[] cookies = request.getCookies(); + if (cookies != null) { for (Cookie cookie : cookies) { if (cookie.getName().equals(name)) { - return cookie; - } - } - } - return null; - } - - /** - * {@inheritDoc} - */ - public String getHeader( HttpServletRequest request, String name ) throws ValidationException { - SecurityConfiguration sc = ESAPI.securityConfiguration(); + return cookie; + } + } + } + return null; + } + + /** + * {@inheritDoc} + */ + public String getHeader( HttpServletRequest request, String name ) throws ValidationException { + SecurityConfiguration sc = ESAPI.securityConfiguration(); String value = request.getHeader(name); return ESAPI.validator().getValidInput("HTTP header value: " + value, value, "HTTPHeaderValue", sc.getIntProp("HttpUtilities.MaxHeaderValueSize"), false); - } + } - /** - * {@inheritDoc} - */ + /** + * {@inheritDoc} + */ public String getHeader( String name ) throws ValidationException { - return getHeader( getCurrentRequest(), name ); + return getHeader( getCurrentRequest(), name ); } /** - * {@inheritDoc} - */ - public String getParameter( HttpServletRequest request, String name ) throws ValidationException { - String value = request.getParameter(name); - return ESAPI.validator().getValidInput("HTTP parameter value: " + value, value, "HTTPParameterValue", 2000, true); - } - - /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ + public String getParameter( HttpServletRequest request, String name ) throws ValidationException { + String value = request.getParameter(name); + return ESAPI.validator().getValidInput("HTTP parameter value: " + value, value, "HTTPParameterValue", 2000, true); + } + + /** + * {@inheritDoc} + */ public String getParameter( String name ) throws ValidationException { - return getParameter( getCurrentRequest(), name ); + return getParameter( getCurrentRequest(), name ); } - /** - * {@inheritDoc} - */ + /** + * {@inheritDoc} + */ public void killAllCookies() { - killAllCookies( getCurrentRequest(), getCurrentResponse() ); + killAllCookies( getCurrentRequest(), getCurrentResponse() ); } - /** - * {@inheritDoc} + /** + * {@inheritDoc} * * @param request * @param response */ - public void killAllCookies(HttpServletRequest request, HttpServletResponse response) { - Cookie[] cookies = request.getCookies(); - if (cookies != null) { + public void killAllCookies(HttpServletRequest request, HttpServletResponse response) { + Cookie[] cookies = request.getCookies(); + if (cookies != null) { for (Cookie cookie : cookies) { - killCookie(request, response, cookie.getName()); - } - } - } + killCookie(request, response, cookie.getName()); + } + } + } - /** - * {@inheritDoc} + /** + * {@inheritDoc} * * @param request * @param response * @param name */ - public void killCookie(HttpServletRequest request, HttpServletResponse response, String name) { - String path = "/"; - String domain=""; - Cookie cookie = getFirstCookie(request, name); - if ( cookie != null ) { - path = cookie.getPath(); - domain = cookie.getDomain(); - } - Cookie deleter = new Cookie( name, "deleted" ); - deleter.setMaxAge( 0 ); - if ( domain != null ) deleter.setDomain( domain ); - if ( path != null ) deleter.setPath( path ); - response.addCookie( deleter ); - } - - - /** - * {@inheritDoc} - */ + public void killCookie(HttpServletRequest request, HttpServletResponse response, String name) { + String path = "/"; + String domain=""; + Cookie cookie = getFirstCookie(request, name); + if ( cookie != null ) { + path = cookie.getPath(); + domain = cookie.getDomain(); + } + Cookie deleter = new Cookie( name, "deleted" ); + deleter.setMaxAge( 0 ); + if ( domain != null ) deleter.setDomain( domain ); + if ( path != null ) deleter.setPath( path ); + response.addCookie( deleter ); + } + + + /** + * {@inheritDoc} + */ public void killCookie( String name ) { - killCookie( getCurrentRequest(), getCurrentResponse(), name ); + killCookie( getCurrentRequest(), getCurrentResponse(), name ); } - /** - * {@inheritDoc} - */ + /** + * {@inheritDoc} + */ public void logHTTPRequest() { - logHTTPRequest( getCurrentRequest(), logger, null ); + logHTTPRequest( getCurrentRequest(), logger, null ); } - /** - * {@inheritDoc} - */ + /** + * {@inheritDoc} + */ public void logHTTPRequest(HttpServletRequest request, Logger logger) { - logHTTPRequest( request, logger, null ); - } - - /** - * Formats an HTTP request into a log suitable string. This implementation logs the remote host IP address (or - * hostname if available), the request method (GET/POST), the URL, and all the querystring and form parameters. All - * the parameters are presented as though they were in the URL even if they were in a form. Any parameters that - * match items in the parameterNamesToObfuscate are shown as eight asterisks. - * - * - * @param request - */ - public void logHTTPRequest(HttpServletRequest request, Logger logger, List parameterNamesToObfuscate) { - StringBuilder params = new StringBuilder(); - Iterator i = request.getParameterMap().keySet().iterator(); - while (i.hasNext()) { - String key = (String) i.next(); - String[] value = request.getParameterMap().get(key); - for (int j = 0; j < value.length; j++) { + logHTTPRequest( request, logger, null ); + } + + /** + * Formats an HTTP request into a log suitable string. This implementation logs the remote host IP address (or + * hostname if available), the request method (GET/POST), the URL, and all the querystring and form parameters. All + * the parameters are presented as though they were in the URL even if they were in a form. Any parameters that + * match items in the parameterNamesToObfuscate are shown as eight asterisks. + * + * + * @param request + */ + public void logHTTPRequest(HttpServletRequest request, Logger logger, List parameterNamesToObfuscate) { + StringBuilder params = new StringBuilder(); + Iterator i = request.getParameterMap().keySet().iterator(); + while (i.hasNext()) { + String key = (String) i.next(); + String[] value = request.getParameterMap().get(key); + for (int j = 0; j < value.length; j++) { params.append(key).append("="); - if (parameterNamesToObfuscate != null && parameterNamesToObfuscate.contains(key)) { - params.append("********"); - } else { - params.append(value[j]); - } - if (j < value.length - 1) { - params.append("&"); - } - } - if (i.hasNext()) - params.append("&"); - } - Cookie[] cookies = request.getCookies(); - if ( cookies != null ) { + if (parameterNamesToObfuscate != null && parameterNamesToObfuscate.contains(key)) { + params.append("********"); + } else { + params.append(value[j]); + } + if (j < value.length - 1) { + params.append("&"); + } + } + if (i.hasNext()) + params.append("&"); + } + Cookie[] cookies = request.getCookies(); + if ( cookies != null ) { for (Cookie cooky : cookies) { if (!cooky.getName().equals(ESAPI.securityConfiguration().getHttpSessionIdName())) { params.append("+").append(cooky.getName()).append("=").append(cooky.getValue()); - } - } - } - String msg = request.getMethod() + " " + request.getRequestURL() + (params.length() > 0 ? "?" + params : ""); - logger.info(Logger.SECURITY_SUCCESS, msg); - } - - private Map queryToMap(String query) { - TreeMap map = new TreeMap(); - String[] parts = query.split("&"); + } + } + } + String msg = request.getMethod() + " " + request.getRequestURL() + (params.length() > 0 ? "?" + params : ""); + logger.info(Logger.SECURITY_SUCCESS, msg); + } + + private Map queryToMap(String query) { + TreeMap map = new TreeMap(); + String[] parts = query.split("&"); for (String part : parts) { try { String[] nvpair = part.split("="); - String name = ESAPI.encoder().decodeFromURL(nvpair[0]); - String value = ESAPI.encoder().decodeFromURL(nvpair[1]); + String name = ESAPI.encoder().decodeFromURL(nvpair[0]); + String value = ESAPI.encoder().decodeFromURL(nvpair[1]); map.put(name, value); } catch (EncodingException e) { - // skip the nvpair with the encoding problem - note this is already logged. - } - } - return map; - } - - /** - * {@inheritDoc} - * - * This implementation simply checks to make sure that the forward location starts with "WEB-INF" and - * is intended for use in frameworks that forward to JSP files inside the WEB-INF folder. - */ - public void sendForward(HttpServletRequest request, HttpServletResponse response, String location) throws AccessControlException,ServletException,IOException { - if (!location.startsWith("WEB-INF")) { - throw new AccessControlException("Forward failed", "Bad forward location: " + location); - } - RequestDispatcher dispatcher = request.getRequestDispatcher(location); - dispatcher.forward( request, response ); - } - - /** - * {@inheritDoc} - */ + // skip the nvpair with the encoding problem - note this is already logged. + } + } + return map; + } + + /** + * {@inheritDoc} + * + * This implementation simply checks to make sure that the forward location starts with "WEB-INF" and + * is intended for use in frameworks that forward to JSP files inside the WEB-INF folder. + */ + public void sendForward(HttpServletRequest request, HttpServletResponse response, String location) throws AccessControlException,ServletException,IOException { + if (!location.startsWith("WEB-INF")) { + throw new AccessControlException("Forward failed", "Bad forward location: " + location); + } + RequestDispatcher dispatcher = request.getRequestDispatcher(location); + dispatcher.forward( request, response ); + } + + /** + * {@inheritDoc} + */ public void sendForward( String location ) throws AccessControlException,ServletException,IOException { - sendForward( getCurrentRequest(), getCurrentResponse(), location); + sendForward( getCurrentRequest(), getCurrentResponse(), location); } - /** - * {@inheritDoc} - * - * This implementation checks against the list of safe redirect locations defined in ESAPI.properties. + /** + * {@inheritDoc} + * + * This implementation checks against the list of safe redirect locations defined in ESAPI.properties. */ public void sendRedirect(HttpServletResponse response, String location) throws AccessControlException, IOException { if (!ESAPI.validator().isValidRedirectLocation("Redirect", location, false)) { @@ -854,42 +854,42 @@ public void sendRedirect(HttpServletResponse response, String location) throws A response.sendRedirect(location); } - /** - * {@inheritDoc} - */ + /** + * {@inheritDoc} + */ public void sendRedirect( String location ) throws AccessControlException,IOException { - sendRedirect( getCurrentResponse(), location); + sendRedirect( getCurrentResponse(), location); } - /** - * {@inheritDoc} - */ + /** + * {@inheritDoc} + */ public void setContentType() { - setContentType( getCurrentResponse() ); + setContentType( getCurrentResponse() ); } - /** - * {@inheritDoc} - */ - public void setContentType(HttpServletResponse response) { - response.setContentType((ESAPI.securityConfiguration()).getResponseContentType()); - } + /** + * {@inheritDoc} + */ + public void setContentType(HttpServletResponse response) { + response.setContentType((ESAPI.securityConfiguration()).getResponseContentType()); + } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public void setCurrentHTTP(HttpServletRequest request, HttpServletResponse response) { - currentRequest.setRequest(request); + currentRequest.setRequest(request); currentResponse.setResponse(response); } /** - * {@inheritDoc} + * {@inheritDoc} */ public void setHeader(HttpServletResponse response, String name, String value) { try { - SecurityConfiguration sc = ESAPI.securityConfiguration(); + SecurityConfiguration sc = ESAPI.securityConfiguration(); String strippedName = StringUtilities.replaceLinearWhiteSpace(name); String strippedValue = StringUtilities.replaceLinearWhiteSpace(value); String safeName = ESAPI.validator().getValidInput("setHeader", strippedName, "HTTPHeaderName", sc.getIntProp("HttpUtilities.MaxHeaderNameSize"), false); @@ -901,145 +901,145 @@ public void setHeader(HttpServletResponse response, String name, String value) { } - /** - * {@inheritDoc} - */ + /** + * {@inheritDoc} + */ public void setHeader( String name, String value ) { - setHeader( getCurrentResponse(), name, value ); + setHeader( getCurrentResponse(), name, value ); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public void setNoCacheHeaders() { - setNoCacheHeaders( getCurrentResponse() ); + setNoCacheHeaders( getCurrentResponse() ); } - /** - * {@inheritDoc} + /** + * {@inheritDoc} * * @param response */ - public void setNoCacheHeaders(HttpServletResponse response) { - // HTTP 1.1 - response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate"); - - // HTTP 1.0 - response.setHeader("Pragma","no-cache"); - response.setDateHeader("Expires", -1); - } - - /** - * {@inheritDoc} - * - * Save the user's remember me data in an encrypted cookie and send it to the user. - * Any old remember me cookie is destroyed first. Setting this cookie will keep the user - * logged in until the maxAge passes, the password is changed, or the cookie is deleted. - * If the cookie exists for the current user, it will automatically be used by ESAPI to - * log the user in, if the data is valid and not expired. + public void setNoCacheHeaders(HttpServletResponse response) { + // HTTP 1.1 + response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate"); + + // HTTP 1.0 + response.setHeader("Pragma","no-cache"); + response.setDateHeader("Expires", -1); + } + + /** + * {@inheritDoc} + * + * Save the user's remember me data in an encrypted cookie and send it to the user. + * Any old remember me cookie is destroyed first. Setting this cookie will keep the user + * logged in until the maxAge passes, the password is changed, or the cookie is deleted. + * If the cookie exists for the current user, it will automatically be used by ESAPI to + * log the user in, if the data is valid and not expired. * * @param request * @param response */ - public String setRememberToken( HttpServletRequest request, HttpServletResponse response, String password, int maxAge, String domain, String path ) { - User user = ESAPI.authenticator().getCurrentUser(); - try { - killCookie(request, response, REMEMBER_TOKEN_COOKIE_NAME ); - // seal already contains random data - String clearToken = user.getAccountName() + "|" + password; - long expiry = ESAPI.encryptor().getRelativeTimeStamp(maxAge * 1000); - String cryptToken = ESAPI.encryptor().seal(clearToken, expiry); - SecurityConfiguration sg = ESAPI.securityConfiguration(); - boolean forceSecureCookies = sg.getBooleanProp("HttpUtilities.ForceSecureCookies"); - boolean forceHttpOnly = sg.getBooleanProp("HttpUtilities.ForceHttpOnlyCookies"); + public String setRememberToken( HttpServletRequest request, HttpServletResponse response, String password, int maxAge, String domain, String path ) { + User user = ESAPI.authenticator().getCurrentUser(); + try { + killCookie(request, response, REMEMBER_TOKEN_COOKIE_NAME ); + // seal already contains random data + String clearToken = user.getAccountName() + "|" + password; + long expiry = ESAPI.encryptor().getRelativeTimeStamp(maxAge * 1000); + String cryptToken = ESAPI.encryptor().seal(clearToken, expiry); + SecurityConfiguration sg = ESAPI.securityConfiguration(); + boolean forceSecureCookies = sg.getBooleanProp("HttpUtilities.ForceSecureCookies"); + boolean forceHttpOnly = sg.getBooleanProp("HttpUtilities.ForceHttpOnlyCookies"); // Do NOT URLEncode cryptToken before creating cookie. See Google Issue # 144, - // which was marked as "WontFix". - - Cookie cookie = new Cookie( REMEMBER_TOKEN_COOKIE_NAME, cryptToken ); - cookie.setMaxAge( maxAge ); - cookie.setDomain( domain ); - cookie.setPath( path ); - cookie.setHttpOnly(forceHttpOnly); - cookie.setSecure(forceSecureCookies); - response.addCookie( cookie ); - logger.info(Logger.SECURITY_SUCCESS, "Enabled remember me token for " + user.getAccountName() ); - return cryptToken; - } catch( IntegrityException e ) { - logger.warning(Logger.SECURITY_FAILURE, "Attempt to set remember me token failed for " + user.getAccountName(), e ); - return null; - } - } - - - public String setRememberToken(HttpServletRequest request, HttpServletResponse response, int maxAge, String domain, String path){ - String rval = ""; - User user = ESAPI.authenticator().getCurrentUser(); - - try{ - killCookie(request,response, REMEMBER_TOKEN_COOKIE_NAME); - // seal already contains random data - String clearToken = user.getAccountName(); - long expiry = ESAPI.encryptor().getRelativeTimeStamp(maxAge * 1000); - String cryptToken = ESAPI.encryptor().seal(clearToken, expiry); - SecurityConfiguration sg = ESAPI.securityConfiguration(); - boolean forceSecureCookies = sg.getBooleanProp("HttpUtilities.ForceSecureCookies"); - boolean forceHttpOnly = sg.getBooleanProp("HttpUtilities.ForceHttpOnlyCookies"); + // which was marked as "WontFix". + + Cookie cookie = new Cookie( REMEMBER_TOKEN_COOKIE_NAME, cryptToken ); + cookie.setMaxAge( maxAge ); + cookie.setDomain( domain ); + cookie.setPath( path ); + cookie.setHttpOnly(forceHttpOnly); + cookie.setSecure(forceSecureCookies); + response.addCookie( cookie ); + logger.info(Logger.SECURITY_SUCCESS, "Enabled remember me token for " + user.getAccountName() ); + return cryptToken; + } catch( IntegrityException e ) { + logger.warning(Logger.SECURITY_FAILURE, "Attempt to set remember me token failed for " + user.getAccountName(), e ); + return null; + } + } + + + public String setRememberToken(HttpServletRequest request, HttpServletResponse response, int maxAge, String domain, String path){ + String rval = ""; + User user = ESAPI.authenticator().getCurrentUser(); + + try{ + killCookie(request,response, REMEMBER_TOKEN_COOKIE_NAME); + // seal already contains random data + String clearToken = user.getAccountName(); + long expiry = ESAPI.encryptor().getRelativeTimeStamp(maxAge * 1000); + String cryptToken = ESAPI.encryptor().seal(clearToken, expiry); + SecurityConfiguration sg = ESAPI.securityConfiguration(); + boolean forceSecureCookies = sg.getBooleanProp("HttpUtilities.ForceSecureCookies"); + boolean forceHttpOnly = sg.getBooleanProp("HttpUtilities.ForceHttpOnlyCookies"); // Do NOT URLEncode cryptToken before creating cookie. See Google Issue # 144, - // which was marked as "WontFix". - - Cookie cookie = new Cookie( REMEMBER_TOKEN_COOKIE_NAME, cryptToken ); - cookie.setMaxAge( maxAge ); - cookie.setDomain( domain ); - cookie.setPath( path ); - cookie.setHttpOnly(forceHttpOnly); - cookie.setSecure(forceSecureCookies); - response.addCookie( cookie ); - logger.info(Logger.SECURITY_SUCCESS, "Enabled remember me token for " + user.getAccountName() ); - } catch( IntegrityException e){ - logger.warning(Logger.SECURITY_FAILURE, "Attempt to set remember me token failed for " + user.getAccountName(), e ); - return null; - } - - - return rval; - } + // which was marked as "WontFix". + + Cookie cookie = new Cookie( REMEMBER_TOKEN_COOKIE_NAME, cryptToken ); + cookie.setMaxAge( maxAge ); + cookie.setDomain( domain ); + cookie.setPath( path ); + cookie.setHttpOnly(forceHttpOnly); + cookie.setSecure(forceSecureCookies); + response.addCookie( cookie ); + logger.info(Logger.SECURITY_SUCCESS, "Enabled remember me token for " + user.getAccountName() ); + } catch( IntegrityException e){ + logger.warning(Logger.SECURITY_FAILURE, "Attempt to set remember me token failed for " + user.getAccountName(), e ); + return null; + } + + + return rval; + } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String setRememberToken( String password, int maxAge, String domain, String path ) { - return setRememberToken( getCurrentRequest(), getCurrentResponse(), password, maxAge, domain, path ); + return setRememberToken( getCurrentRequest(), getCurrentResponse(), password, maxAge, domain, path ); } /** - * {@inheritDoc} - */ - public void verifyCSRFToken() throws IntrusionException { - verifyCSRFToken( getCurrentRequest() ); + * {@inheritDoc} + */ + public void verifyCSRFToken() throws IntrusionException { + verifyCSRFToken( getCurrentRequest() ); } /** - * {@inheritDoc} - * - * This implementation uses the CSRF_TOKEN_NAME parameter for the token. + * {@inheritDoc} + * + * This implementation uses the CSRF_TOKEN_NAME parameter for the token. * * @param request */ - public void verifyCSRFToken(HttpServletRequest request) throws IntrusionException { - User user = ESAPI.authenticator().getCurrentUser(); - - // check if user authenticated with this request - no CSRF protection required - if( request.getAttribute(user.getCSRFToken()) != null ) { - return; - } - String token = request.getParameter(CSRF_TOKEN_NAME); - if ( !user.getCSRFToken().equals( token ) ) { - throw new IntrusionException("Authentication failed", "Possibly forged HTTP request without proper CSRF token detected"); - } - } + public void verifyCSRFToken(HttpServletRequest request) throws IntrusionException { + User user = ESAPI.authenticator().getCurrentUser(); + + // check if user authenticated with this request - no CSRF protection required + if( request.getAttribute(user.getCSRFToken()) != null ) { + return; + } + String token = request.getParameter(CSRF_TOKEN_NAME); + if ( !user.getCSRFToken().equals( token ) ) { + throw new IntrusionException("Authentication failed", "Possibly forged HTTP request without proper CSRF token detected"); + } + } /** * {@inheritDoc} diff --git a/src/main/java/org/owasp/esapi/reference/DefaultIntrusionDetector.java b/src/main/java/org/owasp/esapi/reference/DefaultIntrusionDetector.java index d7b8f2b55..53910bcbf 100644 --- a/src/main/java/org/owasp/esapi/reference/DefaultIntrusionDetector.java +++ b/src/main/java/org/owasp/esapi/reference/DefaultIntrusionDetector.java @@ -47,20 +47,20 @@ */ public class DefaultIntrusionDetector implements org.owasp.esapi.IntrusionDetector { - /** The logger. */ - private final Logger logger = ESAPI.getLogger("IntrusionDetector"); + /** The logger. */ + private final Logger logger = ESAPI.getLogger("IntrusionDetector"); public DefaultIntrusionDetector() { - } - - /** - * {@inheritDoc} + } + + /** + * {@inheritDoc} * * @param e */ - public void addException(Exception e) { - if (ESAPI.securityConfiguration().getDisableIntrusionDetection()) return; - + public void addException(Exception e) { + if (ESAPI.securityConfiguration().getDisableIntrusionDetection()) return; + if ( e instanceof EnterpriseSecurityException ) { logger.warning( Logger.SECURITY_FAILURE, ((EnterpriseSecurityException)e).getLogMessage(), e ); } else { @@ -68,7 +68,7 @@ public void addException(Exception e) { } // add the exception to the current user, which may trigger a detector - User user = ESAPI.authenticator().getCurrentUser(); + User user = ESAPI.authenticator().getCurrentUser(); String eventName = e.getClass().getName(); if ( e instanceof IntrusionException) { @@ -76,9 +76,9 @@ public void addException(Exception e) { } // add the exception to the user's store, handle IntrusionException if thrown - try { - addSecurityEvent(user, eventName); - } catch( IntrusionException ex ) { + try { + addSecurityEvent(user, eventName); + } catch( IntrusionException ex ) { Threshold quota = ESAPI.securityConfiguration().getQuota(eventName); Iterator i = quota.actions.iterator(); while ( i.hasNext() ) { @@ -86,15 +86,15 @@ public void addException(Exception e) { String message = "User exceeded quota of " + quota.count + " per "+ quota.interval +" seconds for event " + eventName + ". Taking actions " + quota.actions; takeSecurityAction( action, message ); } - } - } + } + } - /** - * {@inheritDoc} - */ + /** + * {@inheritDoc} + */ public void addEvent(String eventName, String logMessage) throws IntrusionException { - if (ESAPI.securityConfiguration().getDisableIntrusionDetection()) return; - + if (ESAPI.securityConfiguration().getDisableIntrusionDetection()) return; + logger.warning( Logger.SECURITY_FAILURE, "Security event " + eventName + " received : " + logMessage ); // add the event to the current user, which may trigger a detector @@ -117,19 +117,19 @@ public void addEvent(String eventName, String logMessage) throws IntrusionExcept * actions are: log, disable, logout. * * @param action - * the action to take (log, disable, logout) + * the action to take (log, disable, logout) * @param message - * the message to log if the action is "log" + * the message to log if the action is "log" */ private void takeSecurityAction( String action, String message ) { - if (ESAPI.securityConfiguration().getDisableIntrusionDetection()) return; - + if (ESAPI.securityConfiguration().getDisableIntrusionDetection()) return; + if ( action.equals( "log" ) ) { logger.fatal( Logger.SECURITY_FAILURE, "INTRUSION - " + message ); } User user = ESAPI.authenticator().getCurrentUser(); if (user == User.ANONYMOUS) - return; + return; if ( action.equals( "disable" ) ) { user.disable(); } @@ -138,34 +138,34 @@ private void takeSecurityAction( String action, String message ) { } } - /** - * Adds a security event to the user. These events are used to check that the user has not - * reached the security thresholds set in the properties file. - * - * @param user - * The user that caused the event. - * @param eventName - * The name of the event that occurred. - */ - private void addSecurityEvent(User user, String eventName) { - if (ESAPI.securityConfiguration().getDisableIntrusionDetection()) return; - - if ( user.isAnonymous() ) return; - - HashMap eventMap = user.getEventMap(); - - // if there is a threshold, then track this event - Threshold threshold = ESAPI.securityConfiguration().getQuota( eventName ); - if ( threshold != null ) { - Event event = (Event)eventMap.get( eventName ); - if ( event == null ) { - event = new Event( eventName ); - eventMap.put( eventName, event ); - } - // increment - event.increment(threshold.count, threshold.interval); - } - } + /** + * Adds a security event to the user. These events are used to check that the user has not + * reached the security thresholds set in the properties file. + * + * @param user + * The user that caused the event. + * @param eventName + * The name of the event that occurred. + */ + private void addSecurityEvent(User user, String eventName) { + if (ESAPI.securityConfiguration().getDisableIntrusionDetection()) return; + + if ( user.isAnonymous() ) return; + + HashMap eventMap = user.getEventMap(); + + // if there is a threshold, then track this event + Threshold threshold = ESAPI.securityConfiguration().getQuota( eventName ); + if ( threshold != null ) { + Event event = (Event)eventMap.get( eventName ); + if ( event == null ) { + event = new Event( eventName ); + eventMap.put( eventName, event ); + } + // increment + event.increment(threshold.count, threshold.interval); + } + } private static class Event { public String key; @@ -175,8 +175,8 @@ public Event( String key ) { this.key = key; } public void increment(int count, long interval) throws IntrusionException { - if (ESAPI.securityConfiguration().getDisableIntrusionDetection()) return; - + if (ESAPI.securityConfiguration().getDisableIntrusionDetection()) return; + Date now = new Date(); times.add( 0, now ); while ( times.size() > count ) times.remove( times.size()-1 ); diff --git a/src/main/java/org/owasp/esapi/reference/DefaultRandomizer.java b/src/main/java/org/owasp/esapi/reference/DefaultRandomizer.java index d7731c57b..6d4d65eb0 100644 --- a/src/main/java/org/owasp/esapi/reference/DefaultRandomizer.java +++ b/src/main/java/org/owasp/esapi/reference/DefaultRandomizer.java @@ -65,10 +65,10 @@ private DefaultRandomizer() { } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getRandomString(int length, char[] characterSet) { - StringBuilder sb = new StringBuilder(); + StringBuilder sb = new StringBuilder(); for (int loop = 0; loop < length; loop++) { int index = secureRandom.nextInt(characterSet.length); sb.append(characterSet[index]); @@ -78,37 +78,37 @@ public String getRandomString(int length, char[] characterSet) { } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public boolean getRandomBoolean() { return secureRandom.nextBoolean(); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public int getRandomInteger(int min, int max) { return secureRandom.nextInt(max - min) + min; } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public long getRandomLong() { return secureRandom.nextLong(); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public float getRandomReal(float min, float max) { float factor = max - min; return secureRandom.nextFloat() * factor + min; } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getRandomFilename(String extension) { String fn = getRandomString(12, EncoderConstants.CHAR_ALPHANUMERICS) + "." + extension; logger.debug(Logger.SECURITY_SUCCESS, "Generated new random filename: " + fn ); @@ -116,19 +116,19 @@ public String getRandomFilename(String extension) { } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getRandomGUID() throws EncryptionException { - return UUID.randomUUID().toString(); + return UUID.randomUUID().toString(); } - + /** * {@inheritDoc} */ public byte[] getRandomBytes(int n) { - byte[] result = new byte[ n ]; - secureRandom.nextBytes(result); - return result; + byte[] result = new byte[ n ]; + secureRandom.nextBytes(result); + return result; } - + } diff --git a/src/main/java/org/owasp/esapi/reference/DefaultSecurityConfiguration.java b/src/main/java/org/owasp/esapi/reference/DefaultSecurityConfiguration.java index 3e80055d3..c64cb2694 100644 --- a/src/main/java/org/owasp/esapi/reference/DefaultSecurityConfiguration.java +++ b/src/main/java/org/owasp/esapi/reference/DefaultSecurityConfiguration.java @@ -49,7 +49,7 @@ * 2) Inside the System.getProperty( "org.owasp.esapi.resources" ) directory. * You can set this on the java command line as follows (for example): *
    - * 		java -Dorg.owasp.esapi.resources="C:\temp\resources"
    + *         java -Dorg.owasp.esapi.resources="C:\temp\resources"
      * 
    * You may have to add this to the start-up script that starts your web server. For example, for Tomcat, * in the "catalina" script that starts Tomcat, you can set the JAVA_OPTS variable to the {@code -D} string above. @@ -84,12 +84,12 @@ public static SecurityConfiguration getInstance() { } private Properties properties = null; - private String cipherXformFromESAPIProp = null; // New in ESAPI 2.0 - private String cipherXformCurrent = null; // New in ESAPI 2.0 + private String cipherXformFromESAPIProp = null; // New in ESAPI 2.0 + private String cipherXformCurrent = null; // New in ESAPI 2.0 - /** The name of the ESAPI property file */ - public static final String DEFAULT_RESOURCE_FILE = "ESAPI.properties"; - + /** The name of the ESAPI property file */ + public static final String DEFAULT_RESOURCE_FILE = "ESAPI.properties"; + public static final String REMEMBER_TOKEN_DURATION = "Authenticator.RememberTokenDuration"; public static final String IDLE_TIMEOUT_DURATION = "Authenticator.IdleTimeoutDuration"; public static final String ABSOLUTE_TIMEOUT_DURATION = "Authenticator.AbsoluteTimeoutDuration"; @@ -99,7 +99,7 @@ public static SecurityConfiguration getInstance() { public static final String MAX_OLD_PASSWORD_HASHES = "Authenticator.MaxOldPasswordHashes"; public static final String ALLOW_MULTIPLE_ENCODING = "Encoder.AllowMultipleEncoding"; - public static final String ALLOW_MIXED_ENCODING = "Encoder.AllowMixedEncoding"; + public static final String ALLOW_MIXED_ENCODING = "Encoder.AllowMixedEncoding"; public static final String CANONICALIZATION_CODECS = "Encoder.DefaultCodecList"; public static final String DISABLE_INTRUSION_DETECTION = "IntrusionDetector.Disable"; @@ -114,9 +114,9 @@ public static SecurityConfiguration getInstance() { public static final String RANDOM_ALGORITHM = "Encryptor.RandomAlgorithm"; public static final String DIGITAL_SIGNATURE_ALGORITHM = "Encryptor.DigitalSignatureAlgorithm"; public static final String DIGITAL_SIGNATURE_KEY_LENGTH = "Encryptor.DigitalSignatureKeyLength"; - // ==================================// - // New in ESAPI Java 2.x // - // ================================= // + // ==================================// + // New in ESAPI Java 2.x // + // ================================= // public static final String PREFERRED_JCE_PROVIDER = "Encryptor.PreferredJCEProvider"; public static final String CIPHER_TRANSFORMATION_IMPLEMENTATION = "Encryptor.CipherTransformation"; public static final String CIPHERTEXT_USE_MAC = "Encryptor.CipherText.useMAC"; @@ -128,7 +128,7 @@ public static SecurityConfiguration getInstance() { public static final String COMBINED_CIPHER_MODES = "Encryptor.cipher_modes.combined_modes"; public static final String ADDITIONAL_ALLOWED_CIPHER_MODES = "Encryptor.cipher_modes.additional_allowed"; public static final String KDF_PRF_ALG = "Encryptor.KDF.PRF"; - public static final String PRINT_PROPERTIES_WHEN_LOADED = "ESAPI.printProperties"; + public static final String PRINT_PROPERTIES_WHEN_LOADED = "ESAPI.printProperties"; public static final String WORKING_DIRECTORY = "Executor.WorkingDirectory"; public static final String APPROVED_EXECUTABLES = "Executor.ApprovedExecutables"; @@ -137,7 +137,7 @@ public static SecurityConfiguration getInstance() { public static final String FORCE_SECURESESSION = "HttpUtilities.SecureSession"; public static final String FORCE_HTTPONLYCOOKIES = "HttpUtilities.ForceHttpOnlyCookies"; public static final String FORCE_SECURECOOKIES = "HttpUtilities.ForceSecureCookies"; - public static final String MAX_HTTP_HEADER_SIZE = "HttpUtilities.MaxHeaderSize"; + public static final String MAX_HTTP_HEADER_SIZE = "HttpUtilities.MaxHeaderSize"; public static final String UPLOAD_DIRECTORY = "HttpUtilities.UploadDir"; public static final String UPLOAD_TEMP_DIRECTORY = "HttpUtilities.UploadTempDir"; public static final String APPROVED_UPLOAD_EXTENSIONS = "HttpUtilities.ApprovedUploadExtensions"; @@ -155,7 +155,7 @@ public static SecurityConfiguration getInstance() { public static final String VALIDATION_PROPERTIES_MULTIVALUED = "Validator.ConfigurationFile.MultiValued"; public static final String ACCEPT_LENIENT_DATES = "Validator.AcceptLenientDates"; public static final String VALIDATOR_HTML_VALIDATION_ACTION = "Validator.HtmlValidationAction"; - public static final String VALIDATOR_HTML_VALIDATION_CONFIGURATION_FILE = "Validator.HtmlValidationConfigurationFile"; + public static final String VALIDATOR_HTML_VALIDATION_CONFIGURATION_FILE = "Validator.HtmlValidationConfigurationFile"; /** * Special {@code System} property that, if set to {@code true}, will @@ -182,9 +182,9 @@ public static SecurityConfiguration getInstance() { public static final String ENCRYPTION_IMPLEMENTATION = "ESAPI.Encryptor"; public static final String INTRUSION_DETECTION_IMPLEMENTATION = "ESAPI.IntrusionDetector"; public static final String RANDOMIZER_IMPLEMENTATION = "ESAPI.Randomizer"; - public static final String EXECUTOR_IMPLEMENTATION = "ESAPI.Executor"; - public static final String VALIDATOR_IMPLEMENTATION = "ESAPI.Validator"; - public static final String HTTP_UTILITIES_IMPLEMENTATION = "ESAPI.HTTPUtilities"; + public static final String EXECUTOR_IMPLEMENTATION = "ESAPI.Executor"; + public static final String VALIDATOR_IMPLEMENTATION = "ESAPI.Validator"; + public static final String HTTP_UTILITIES_IMPLEMENTATION = "ESAPI.HTTPUtilities"; /* * Default Implementations @@ -208,16 +208,16 @@ public static SecurityConfiguration getInstance() { private static final String userHome = System.getProperty("user.home" ); /* * Absolute path to the customDirectory - */ // DISCUSS: Implicit assumption here that there is no SecurityManager installed enforcing the - // prevention of reading system properties. Otherwise this will fail with SecurityException. + */ // DISCUSS: Implicit assumption here that there is no SecurityManager installed enforcing the + // prevention of reading system properties. Otherwise this will fail with SecurityException. private static String customDirectory = System.getProperty("org.owasp.esapi.resources"); /* * Relative path to the resourceDirectory. Relative to the classpath. * Specifically, ClassLoader.getResource(resourceDirectory + filename) will * be used to load the file. */ - private String resourceDirectory = ".esapi"; // For backward compatibility (vs. "esapi") - private final String resourceFile; + private String resourceDirectory = ".esapi"; // For backward compatibility (vs. "esapi") + private final String resourceFile; private EsapiPropertyManager esapiPropertyManager; // private static long lastModified = -1; @@ -228,15 +228,15 @@ public static SecurityConfiguration getInstance() { * @param resourceFile The name of the property file to load */ DefaultSecurityConfiguration(String resourceFile) { - this.resourceFile = resourceFile; - // load security configuration - try { + this.resourceFile = resourceFile; + // load security configuration + try { this.esapiPropertyManager = new EsapiPropertyManager(); - loadConfiguration(); - this.setCipherXProperties(); + loadConfiguration(); + this.setCipherXProperties(); } catch( IOException e ) { - logSpecial("Failed to load security configuration", e ); - throw new ConfigurationException("Failed to load security configuration", e); + logSpecial("Failed to load security configuration", e ); + throw new ConfigurationException("Failed to load security configuration", e); } } @@ -249,473 +249,473 @@ public static SecurityConfiguration getInstance() { * @param properties */ public DefaultSecurityConfiguration(Properties properties) { - resourceFile = DEFAULT_RESOURCE_FILE; - try { + resourceFile = DEFAULT_RESOURCE_FILE; + try { this.esapiPropertyManager = new EsapiPropertyManager(); // Do NOT call loadConfiguration() here! } catch( IOException e ) { - logSpecial("Failed to load security configuration", e ); - throw new ConfigurationException("Failed to load security configuration", e); + logSpecial("Failed to load security configuration", e ); + throw new ConfigurationException("Failed to load security configuration", e); } - this.properties = properties; - this.setCipherXProperties(); + this.properties = properties; + this.setCipherXProperties(); } /** * Instantiates a new configuration. */ public DefaultSecurityConfiguration(){ - this(DEFAULT_RESOURCE_FILE); + this(DEFAULT_RESOURCE_FILE); } private void setCipherXProperties() { - // TODO: FUTURE: Replace by future CryptoControls class??? - // See SecurityConfiguration.setCipherTransformation() for - // explanation of this. + // TODO: FUTURE: Replace by future CryptoControls class??? + // See SecurityConfiguration.setCipherTransformation() for + // explanation of this. // (Propose this in a future 2.x release via future email to ESAPI-DEV list.) - cipherXformFromESAPIProp = - getESAPIProperty(CIPHER_TRANSFORMATION_IMPLEMENTATION, - "AES/CBC/PKCS5Padding"); - cipherXformCurrent = cipherXformFromESAPIProp; + cipherXformFromESAPIProp = + getESAPIProperty(CIPHER_TRANSFORMATION_IMPLEMENTATION, + "AES/CBC/PKCS5Padding"); + cipherXformCurrent = cipherXformFromESAPIProp; } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getApplicationName() { - return getESAPIProperty(APPLICATION_NAME, "DefaultName"); + return getESAPIProperty(APPLICATION_NAME, "DefaultName"); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getLogImplementation() { - return getESAPIProperty(LOG_IMPLEMENTATION, DEFAULT_LOG_IMPLEMENTATION); + return getESAPIProperty(LOG_IMPLEMENTATION, DEFAULT_LOG_IMPLEMENTATION); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getAuthenticationImplementation() { - return getESAPIProperty(AUTHENTICATION_IMPLEMENTATION, DEFAULT_AUTHENTICATION_IMPLEMENTATION); + return getESAPIProperty(AUTHENTICATION_IMPLEMENTATION, DEFAULT_AUTHENTICATION_IMPLEMENTATION); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getEncoderImplementation() { - return getESAPIProperty(ENCODER_IMPLEMENTATION, DEFAULT_ENCODER_IMPLEMENTATION); + return getESAPIProperty(ENCODER_IMPLEMENTATION, DEFAULT_ENCODER_IMPLEMENTATION); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getAccessControlImplementation() { - return getESAPIProperty(ACCESS_CONTROL_IMPLEMENTATION, DEFAULT_ACCESS_CONTROL_IMPLEMENTATION); + return getESAPIProperty(ACCESS_CONTROL_IMPLEMENTATION, DEFAULT_ACCESS_CONTROL_IMPLEMENTATION); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getEncryptionImplementation() { - return getESAPIProperty(ENCRYPTION_IMPLEMENTATION, DEFAULT_ENCRYPTION_IMPLEMENTATION); + return getESAPIProperty(ENCRYPTION_IMPLEMENTATION, DEFAULT_ENCRYPTION_IMPLEMENTATION); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getIntrusionDetectionImplementation() { - return getESAPIProperty(INTRUSION_DETECTION_IMPLEMENTATION, DEFAULT_INTRUSION_DETECTION_IMPLEMENTATION); + return getESAPIProperty(INTRUSION_DETECTION_IMPLEMENTATION, DEFAULT_INTRUSION_DETECTION_IMPLEMENTATION); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getRandomizerImplementation() { - return getESAPIProperty(RANDOMIZER_IMPLEMENTATION, DEFAULT_RANDOMIZER_IMPLEMENTATION); + return getESAPIProperty(RANDOMIZER_IMPLEMENTATION, DEFAULT_RANDOMIZER_IMPLEMENTATION); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getExecutorImplementation() { - return getESAPIProperty(EXECUTOR_IMPLEMENTATION, DEFAULT_EXECUTOR_IMPLEMENTATION); + return getESAPIProperty(EXECUTOR_IMPLEMENTATION, DEFAULT_EXECUTOR_IMPLEMENTATION); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getHTTPUtilitiesImplementation() { - return getESAPIProperty(HTTP_UTILITIES_IMPLEMENTATION, DEFAULT_HTTP_UTILITIES_IMPLEMENTATION); + return getESAPIProperty(HTTP_UTILITIES_IMPLEMENTATION, DEFAULT_HTTP_UTILITIES_IMPLEMENTATION); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getValidationImplementation() { - return getESAPIProperty(VALIDATOR_IMPLEMENTATION, DEFAULT_VALIDATOR_IMPLEMENTATION); + return getESAPIProperty(VALIDATOR_IMPLEMENTATION, DEFAULT_VALIDATOR_IMPLEMENTATION); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public byte[] getMasterKey() { - byte[] key = getESAPIPropertyEncoded( MASTER_KEY, null ); - if ( key == null || key.length == 0 ) { - throw new ConfigurationException("Property '" + MASTER_KEY + - "' missing or empty in ESAPI.properties file."); + byte[] key = getESAPIPropertyEncoded( MASTER_KEY, null ); + if ( key == null || key.length == 0 ) { + throw new ConfigurationException("Property '" + MASTER_KEY + + "' missing or empty in ESAPI.properties file."); } - return key; + return key; } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public void setResourceDirectory( String dir ) { - resourceDirectory = dir; + resourceDirectory = dir; logSpecial( "Reset resource directory to: " + dir, null ); // reload configuration if necessary - try { - this.loadConfiguration(); - } catch( IOException e ) { - logSpecial("Failed to load security configuration from " + dir, e); - } + try { + this.loadConfiguration(); + } catch( IOException e ) { + logSpecial("Failed to load security configuration from " + dir, e); + } } public int getEncryptionKeyLength() { - return getESAPIProperty(KEY_LENGTH, 128 ); + return getESAPIProperty(KEY_LENGTH, 128 ); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public byte[] getMasterSalt() { - byte[] salt = getESAPIPropertyEncoded( MASTER_SALT, null ); - if ( salt == null || salt.length == 0 ) { - throw new ConfigurationException("Property '" + MASTER_SALT + - "' missing or empty in ESAPI.properties file."); + byte[] salt = getESAPIPropertyEncoded( MASTER_SALT, null ); + if ( salt == null || salt.length == 0 ) { + throw new ConfigurationException("Property '" + MASTER_SALT + + "' missing or empty in ESAPI.properties file."); } - return salt; + return salt; } /** - * {@inheritDoc} - */ - public List getAllowedExecutables() { - String def = ""; + * {@inheritDoc} + */ + public List getAllowedExecutables() { + String def = ""; String[] exList = getESAPIProperty(APPROVED_EXECUTABLES,def).split(","); return Arrays.asList(exList); } /** - * {@inheritDoc} - */ - public List getAllowedFileExtensions() { + * {@inheritDoc} + */ + public List getAllowedFileExtensions() { String def = ".pdf,.txt,.jpg,.png"; String[] extList = getESAPIProperty(APPROVED_UPLOAD_EXTENSIONS,def).split(","); return Arrays.asList(extList); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public int getAllowedFileUploadSize() { return getESAPIProperty(MAX_UPLOAD_FILE_BYTES, 5000000); } private Properties loadPropertiesFromStream( InputStream is, String name ) throws IOException { - Properties config = new Properties(); + Properties config = new Properties(); try { - config.load(is); - logSpecial("Loaded '" + name + "' properties file", null); + config.load(is); + logSpecial("Loaded '" + name + "' properties file", null); } finally { if ( is != null ) try { is.close(); } catch( Exception e ) {} } return config; } - /** - * Load configuration. Never prints properties. - * - * @throws java.io.IOException - * if the file is inaccessible - */ - protected void loadConfiguration() throws IOException { - try { - //first attempt file IO loading of properties - logSpecial("Attempting to load " + resourceFile + " via file I/O."); - properties = loadPropertiesFromStream(getResourceStream(resourceFile), resourceFile); - - } catch (Exception iae) { - //if file I/O loading fails, attempt classpath based loading next - logSpecial("Loading " + resourceFile + " via file I/O failed. Exception was: " + iae); - logSpecial("Attempting to load " + resourceFile + " via the classpath."); - try { - properties = loadConfigurationFromClasspath(resourceFile); - } catch (Exception e) { - logSpecial(resourceFile + " could not be loaded by any means. Fail.", e); - throw new ConfigurationException(resourceFile + " could not be loaded by any means. Fail.", e); - } - } - - // if properties loaded properly above, get validation properties and merge them into the main properties - if (properties != null) { - final Iterator validationPropFileNames; - - //defaults to single-valued for backwards compatibility - final boolean multivalued= getESAPIProperty(VALIDATION_PROPERTIES_MULTIVALUED, false); - final String validationPropValue = getESAPIProperty(VALIDATION_PROPERTIES, "validation.properties"); - - if(multivalued){ - // the following cast warning goes away if the apache commons lib is updated to current version - validationPropFileNames = StrTokenizer.getCSVInstance(validationPropValue); - } else { - validationPropFileNames = Collections.singletonList(validationPropValue).iterator(); - } - - //clear any cached validation patterns so they can be reloaded from validation.properties - patternCache.clear(); - while(validationPropFileNames.hasNext()){ - String validationPropFileName = validationPropFileNames.next(); - Properties validationProperties = null; - try { - //first attempt file IO loading of properties - logSpecial("Attempting to load " + validationPropFileName + " via file I/O."); - validationProperties = loadPropertiesFromStream(getResourceStream(validationPropFileName), validationPropFileName); - - } catch (Exception iae) { - //if file I/O loading fails, attempt classpath based loading next - logSpecial("Loading " + validationPropFileName + " via file I/O failed."); - logSpecial("Attempting to load " + validationPropFileName + " via the classpath."); - try { - validationProperties = loadConfigurationFromClasspath(validationPropFileName); - } catch (Exception e) { - logSpecial(validationPropFileName + " could not be loaded by any means. fail.", e); - } - } - - if (validationProperties != null) { - Iterator i = validationProperties.keySet().iterator(); - while( i.hasNext() ) { - String key = (String)i.next(); - String value = validationProperties.getProperty(key); - properties.put( key, value); - } - } - - if ( shouldPrintProperties() ) { - - //FIXME - make this chunk configurable - /* - logSpecial(" ========Master Configuration========", null); - //logSpecial( " ResourceDirectory: " + DefaultSecurityConfiguration.resourceDirectory ); - Iterator j = new TreeSet( properties.keySet() ).iterator(); - while (j.hasNext()) { - String key = (String)j.next(); - // print out properties, but not sensitive ones like MasterKey and MasterSalt - if ( !key.contains( "Master" ) ) { - logSpecial(" | " + key + "=" + properties.get(key), null); - } - } - */ - } - } - } - } - - /** - * @param filename - * @return An {@code InputStream} associated with the specified file name as - * a resource stream. - * @throws IOException - * If the file cannot be found or opened for reading. - */ - public InputStream getResourceStream(String filename) throws IOException { - if (filename == null) { - return null; - } - - try { - File f = getResourceFile(filename); - if (f != null && f.exists()) { - return new FileInputStream(f); - } - } catch (Exception e) { - } - - throw new FileNotFoundException(); - } - - /** - * {@inheritDoc} - */ - public File getResourceFile(String filename) { - logSpecial("Attempting to load " + filename + " as resource file via file I/O."); - - if (filename == null) { - logSpecial("Failed to load properties via FileIO. Filename is null."); - return null; // not found. - } - - File f = null; - - // first, allow command line overrides. -Dorg.owasp.esapi.resources - // directory - f = new File(customDirectory, filename); - if (customDirectory != null && f.canRead()) { - logSpecial("Found in 'org.owasp.esapi.resources' directory: " + f.getAbsolutePath()); - return f; - } else { - logSpecial("Not found in 'org.owasp.esapi.resources' directory or file not readable: " + f.getAbsolutePath()); - } - - // if not found, then try the programmatically set resource directory - // (this defaults to SystemResource directory/resourceFile - URL fileUrl = ClassLoader.getSystemResource(resourceDirectory + "/" + filename); + /** + * Load configuration. Never prints properties. + * + * @throws java.io.IOException + * if the file is inaccessible + */ + protected void loadConfiguration() throws IOException { + try { + //first attempt file IO loading of properties + logSpecial("Attempting to load " + resourceFile + " via file I/O."); + properties = loadPropertiesFromStream(getResourceStream(resourceFile), resourceFile); + + } catch (Exception iae) { + //if file I/O loading fails, attempt classpath based loading next + logSpecial("Loading " + resourceFile + " via file I/O failed. Exception was: " + iae); + logSpecial("Attempting to load " + resourceFile + " via the classpath."); + try { + properties = loadConfigurationFromClasspath(resourceFile); + } catch (Exception e) { + logSpecial(resourceFile + " could not be loaded by any means. Fail.", e); + throw new ConfigurationException(resourceFile + " could not be loaded by any means. Fail.", e); + } + } + + // if properties loaded properly above, get validation properties and merge them into the main properties + if (properties != null) { + final Iterator validationPropFileNames; + + //defaults to single-valued for backwards compatibility + final boolean multivalued= getESAPIProperty(VALIDATION_PROPERTIES_MULTIVALUED, false); + final String validationPropValue = getESAPIProperty(VALIDATION_PROPERTIES, "validation.properties"); + + if(multivalued){ + // the following cast warning goes away if the apache commons lib is updated to current version + validationPropFileNames = StrTokenizer.getCSVInstance(validationPropValue); + } else { + validationPropFileNames = Collections.singletonList(validationPropValue).iterator(); + } + + //clear any cached validation patterns so they can be reloaded from validation.properties + patternCache.clear(); + while(validationPropFileNames.hasNext()){ + String validationPropFileName = validationPropFileNames.next(); + Properties validationProperties = null; + try { + //first attempt file IO loading of properties + logSpecial("Attempting to load " + validationPropFileName + " via file I/O."); + validationProperties = loadPropertiesFromStream(getResourceStream(validationPropFileName), validationPropFileName); + + } catch (Exception iae) { + //if file I/O loading fails, attempt classpath based loading next + logSpecial("Loading " + validationPropFileName + " via file I/O failed."); + logSpecial("Attempting to load " + validationPropFileName + " via the classpath."); + try { + validationProperties = loadConfigurationFromClasspath(validationPropFileName); + } catch (Exception e) { + logSpecial(validationPropFileName + " could not be loaded by any means. fail.", e); + } + } + + if (validationProperties != null) { + Iterator i = validationProperties.keySet().iterator(); + while( i.hasNext() ) { + String key = (String)i.next(); + String value = validationProperties.getProperty(key); + properties.put( key, value); + } + } + + if ( shouldPrintProperties() ) { + + //FIXME - make this chunk configurable + /* + logSpecial(" ========Master Configuration========", null); + //logSpecial( " ResourceDirectory: " + DefaultSecurityConfiguration.resourceDirectory ); + Iterator j = new TreeSet( properties.keySet() ).iterator(); + while (j.hasNext()) { + String key = (String)j.next(); + // print out properties, but not sensitive ones like MasterKey and MasterSalt + if ( !key.contains( "Master" ) ) { + logSpecial(" | " + key + "=" + properties.get(key), null); + } + } + */ + } + } + } + } + + /** + * @param filename + * @return An {@code InputStream} associated with the specified file name as + * a resource stream. + * @throws IOException + * If the file cannot be found or opened for reading. + */ + public InputStream getResourceStream(String filename) throws IOException { + if (filename == null) { + return null; + } + + try { + File f = getResourceFile(filename); + if (f != null && f.exists()) { + return new FileInputStream(f); + } + } catch (Exception e) { + } + + throw new FileNotFoundException(); + } + + /** + * {@inheritDoc} + */ + public File getResourceFile(String filename) { + logSpecial("Attempting to load " + filename + " as resource file via file I/O."); + + if (filename == null) { + logSpecial("Failed to load properties via FileIO. Filename is null."); + return null; // not found. + } + + File f = null; + + // first, allow command line overrides. -Dorg.owasp.esapi.resources + // directory + f = new File(customDirectory, filename); + if (customDirectory != null && f.canRead()) { + logSpecial("Found in 'org.owasp.esapi.resources' directory: " + f.getAbsolutePath()); + return f; + } else { + logSpecial("Not found in 'org.owasp.esapi.resources' directory or file not readable: " + f.getAbsolutePath()); + } + + // if not found, then try the programmatically set resource directory + // (this defaults to SystemResource directory/resourceFile + URL fileUrl = ClassLoader.getSystemResource(resourceDirectory + "/" + filename); if ( fileUrl == null ) { fileUrl = ClassLoader.getSystemResource("esapi/" + filename); } - if (fileUrl != null) { - try { - String fileLocation = fileUrl.toURI().getPath(); - f = new File(fileLocation); - if (f.exists()) { - logSpecial("Found in SystemResource Directory/resourceDirectory: " + f.getAbsolutePath()); - return f; - } else { - logSpecial("Not found in SystemResource Directory/resourceDirectory (this should never happen): " + f.getAbsolutePath()); - } - } catch (URISyntaxException e) { - logSpecial("Error while converting URL " + fileUrl + " to file path: " + e.getMessage()); - } - } else { - logSpecial("Not found in SystemResource Directory/resourceDirectory: " + resourceDirectory + File.separator + filename); - } - - // If not found, then try immediately under user's home directory first in - // userHome + "/.esapi" and secondly under - // userHome + "/esapi" - // We look in that order because of backward compatibility issues. - String homeDir = userHome; - if ( homeDir == null ) { - homeDir = ""; // Without this, homeDir + "/.esapi" would produce - // the string "null/.esapi" which surely is not intended. - } - // First look under ".esapi" (for reasons of backward compatibility). - f = new File(homeDir + "/.esapi", filename); - if ( f.canRead() ) { - logSpecial("[Compatibility] Found in 'user.home' directory: " + f.getAbsolutePath()); - return f; - } else { - // Didn't find it under old directory ".esapi" so now look under the "esapi" directory. - f = new File(homeDir + "/esapi", filename); - if ( f.canRead() ) { - logSpecial("Found in 'user.home' directory: " + f.getAbsolutePath()); - return f; - } else { - logSpecial("Not found in 'user.home' (" + homeDir + ") directory: " + f.getAbsolutePath()); - } - } - - // return null if not found - return null; - } - + if (fileUrl != null) { + try { + String fileLocation = fileUrl.toURI().getPath(); + f = new File(fileLocation); + if (f.exists()) { + logSpecial("Found in SystemResource Directory/resourceDirectory: " + f.getAbsolutePath()); + return f; + } else { + logSpecial("Not found in SystemResource Directory/resourceDirectory (this should never happen): " + f.getAbsolutePath()); + } + } catch (URISyntaxException e) { + logSpecial("Error while converting URL " + fileUrl + " to file path: " + e.getMessage()); + } + } else { + logSpecial("Not found in SystemResource Directory/resourceDirectory: " + resourceDirectory + File.separator + filename); + } + + // If not found, then try immediately under user's home directory first in + // userHome + "/.esapi" and secondly under + // userHome + "/esapi" + // We look in that order because of backward compatibility issues. + String homeDir = userHome; + if ( homeDir == null ) { + homeDir = ""; // Without this, homeDir + "/.esapi" would produce + // the string "null/.esapi" which surely is not intended. + } + // First look under ".esapi" (for reasons of backward compatibility). + f = new File(homeDir + "/.esapi", filename); + if ( f.canRead() ) { + logSpecial("[Compatibility] Found in 'user.home' directory: " + f.getAbsolutePath()); + return f; + } else { + // Didn't find it under old directory ".esapi" so now look under the "esapi" directory. + f = new File(homeDir + "/esapi", filename); + if ( f.canRead() ) { + logSpecial("Found in 'user.home' directory: " + f.getAbsolutePath()); + return f; + } else { + logSpecial("Not found in 'user.home' (" + homeDir + ") directory: " + f.getAbsolutePath()); + } + } + + // return null if not found + return null; + } + /** * Used to load ESAPI.properties from a variety of different classpath locations. * * @param fileName The properties file filename. */ - private Properties loadConfigurationFromClasspath(String fileName) throws IllegalArgumentException { - Properties result = null; - InputStream in = null; - - ClassLoader[] loaders = new ClassLoader[] { - Thread.currentThread().getContextClassLoader(), - ClassLoader.getSystemClassLoader(), - getClass().getClassLoader() - }; - String[] classLoaderNames = { - "current thread context class loader", - "system class loader", - "class loader for DefaultSecurityConfiguration class" - }; - - ClassLoader currentLoader = null; - for (int i = 0; i < loaders.length; i++) { - if (loaders[i] != null) { - currentLoader = loaders[i]; - try { - // try root - String currentClasspathSearchLocation = "/ (root)"; + private Properties loadConfigurationFromClasspath(String fileName) throws IllegalArgumentException { + Properties result = null; + InputStream in = null; + + ClassLoader[] loaders = new ClassLoader[] { + Thread.currentThread().getContextClassLoader(), + ClassLoader.getSystemClassLoader(), + getClass().getClassLoader() + }; + String[] classLoaderNames = { + "current thread context class loader", + "system class loader", + "class loader for DefaultSecurityConfiguration class" + }; + + ClassLoader currentLoader = null; + for (int i = 0; i < loaders.length; i++) { + if (loaders[i] != null) { + currentLoader = loaders[i]; + try { + // try root + String currentClasspathSearchLocation = "/ (root)"; // Note: do NOT add '/' anywhere here even though root value is empty string! // Note that since DefaultSearchPath.ROOT.value() is now "" (the empty string), // then this is logically equivalent to what we used to have, which was: // - // in = loaders[i].getResourceAsStream(fileName); + // in = loaders[i].getResourceAsStream(fileName); // - in = loaders[i].getResourceAsStream(DefaultSearchPath.ROOT.value() + fileName); - - // try resourceDirectory folder - if (in == null) { - currentClasspathSearchLocation = resourceDirectory + "/"; - in = currentLoader.getResourceAsStream(DefaultSearchPath.RESOURCE_DIRECTORY.value() + fileName); - } - - // try .esapi folder. Look here first for backward compatibility. - if (in == null) { - currentClasspathSearchLocation = ".esapi/"; - in = currentLoader.getResourceAsStream(DefaultSearchPath.DOT_ESAPI.value() + fileName); - } - - // try esapi folder (new directory) - if (in == null) { - currentClasspathSearchLocation = "esapi/"; - in = currentLoader.getResourceAsStream(DefaultSearchPath.ESAPI.value() + fileName); - } - - // try resources folder - if (in == null) { - currentClasspathSearchLocation = "resources/"; - in = currentLoader.getResourceAsStream(DefaultSearchPath.RESOURCES.value() + fileName); - } - - // try src/main/resources folder - if (in == null) { - currentClasspathSearchLocation = "src/main/resources/"; - in = currentLoader.getResourceAsStream(DefaultSearchPath.SRC_MAIN_RESOURCES.value() + fileName); - } - - // now load the properties - if (in != null) { - result = new Properties(); - result.load(in); // Can throw IOException - logSpecial("SUCCESSFULLY LOADED " + fileName + " via the CLASSPATH from '" + - currentClasspathSearchLocation + "' using " + classLoaderNames[i] + "!"); - break; // Outta here since we've found and loaded it. - } - } catch (Exception e) { - result = null; - - } finally { - try { - in.close(); - } catch (Exception e) { - } - } - } - } - - if (result == null) { - // CHECKME: This is odd...why not ConfigurationException? - throw new IllegalArgumentException("Failed to load " + resourceFile + " as a classloader resource."); - } - - return result; - } + in = loaders[i].getResourceAsStream(DefaultSearchPath.ROOT.value() + fileName); + + // try resourceDirectory folder + if (in == null) { + currentClasspathSearchLocation = resourceDirectory + "/"; + in = currentLoader.getResourceAsStream(DefaultSearchPath.RESOURCE_DIRECTORY.value() + fileName); + } + + // try .esapi folder. Look here first for backward compatibility. + if (in == null) { + currentClasspathSearchLocation = ".esapi/"; + in = currentLoader.getResourceAsStream(DefaultSearchPath.DOT_ESAPI.value() + fileName); + } + + // try esapi folder (new directory) + if (in == null) { + currentClasspathSearchLocation = "esapi/"; + in = currentLoader.getResourceAsStream(DefaultSearchPath.ESAPI.value() + fileName); + } + + // try resources folder + if (in == null) { + currentClasspathSearchLocation = "resources/"; + in = currentLoader.getResourceAsStream(DefaultSearchPath.RESOURCES.value() + fileName); + } + + // try src/main/resources folder + if (in == null) { + currentClasspathSearchLocation = "src/main/resources/"; + in = currentLoader.getResourceAsStream(DefaultSearchPath.SRC_MAIN_RESOURCES.value() + fileName); + } + + // now load the properties + if (in != null) { + result = new Properties(); + result.load(in); // Can throw IOException + logSpecial("SUCCESSFULLY LOADED " + fileName + " via the CLASSPATH from '" + + currentClasspathSearchLocation + "' using " + classLoaderNames[i] + "!"); + break; // Outta here since we've found and loaded it. + } + } catch (Exception e) { + result = null; + + } finally { + try { + in.close(); + } catch (Exception e) { + } + } + } + } + + if (result == null) { + // CHECKME: This is odd...why not ConfigurationException? + throw new IllegalArgumentException("Failed to load " + resourceFile + " as a classloader resource."); + } + + return result; + } /** * Log to standard output (i.e., {@code System.out}. This method is @@ -772,36 +772,36 @@ private void logSpecial(String message, Throwable e) { * @param message The message to send to the console. */ private void logSpecial(String message) { - logToStdout(message, null); + logToStdout(message, null); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getPasswordParameterName() { return getESAPIProperty(PASSWORD_PARAMETER_NAME, "password"); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getUsernameParameterName() { return getESAPIProperty(USERNAME_PARAMETER_NAME, "username"); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getEncryptionAlgorithm() { return getESAPIProperty(ENCRYPTION_ALGORITHM, "AES"); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getCipherTransformation() { // Assertion should be okay here. An NPE is likely at runtime if disabled. - assert cipherXformCurrent != null : "Current cipher transformation is null"; - return cipherXformCurrent; + assert cipherXformCurrent != null : "Current cipher transformation is null"; + return cipherXformCurrent; } /** @@ -825,159 +825,159 @@ public String setCipherTransformation(String cipherXform) { * {@inheritDoc} */ public boolean useMACforCipherText() { - return getESAPIProperty(CIPHERTEXT_USE_MAC, true); + return getESAPIProperty(CIPHERTEXT_USE_MAC, true); } /** * {@inheritDoc} */ public boolean overwritePlainText() { - return getESAPIProperty(PLAINTEXT_OVERWRITE, true); + return getESAPIProperty(PLAINTEXT_OVERWRITE, true); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ @Deprecated public String getIVType() { - String value = getESAPIProperty(IV_TYPE, "random"); - if ( value.equalsIgnoreCase("random") ) { + String value = getESAPIProperty(IV_TYPE, "random"); + if ( value.equalsIgnoreCase("random") ) { return value; } else if ( value.equalsIgnoreCase("fixed") ) { logSpecial("WARNING: Property '" + IV_TYPE + "=fixed' is no longer supported AT ALL!!! It had been deprecated since 2.2.0.0 and back then, was announced it would be removed in release 2.3.0.0. It was originally intended to support legacy applications, but is inherently insecure, especially with any streaming mode."); - throw new ConfigurationException("'" + IV_TYPE + "=fixed' is no longer supported AT ALL. It has been deprecated since release 2.2 and has been removed since 2.3."); - } else if ( value.equalsIgnoreCase("specified") ) { - // Originally, this was planned for future implementation where setting - // Encryptor.ChooseIVMethod=specified + throw new ConfigurationException("'" + IV_TYPE + "=fixed' is no longer supported AT ALL. It has been deprecated since release 2.2 and has been removed since 2.3."); + } else if ( value.equalsIgnoreCase("specified") ) { + // Originally, this was planned for future implementation where setting + // Encryptor.ChooseIVMethod=specified // would have allowed a dev to write their own static method to be // invoked in a future TBD property, but that is a recipe for // disaster. So, it's not going to happen. Ever. - throw new ConfigurationException("Contrary to previous internal comments, '" + IV_TYPE + "=specified' is not going to be supported -- ever."); - } else { - logSpecial("WARNING: '" + value + "' is illegal value for " + IV_TYPE + - ". Using 'random' for the IV type."); - } + throw new ConfigurationException("Contrary to previous internal comments, '" + IV_TYPE + "=specified' is not going to be supported -- ever."); + } else { + logSpecial("WARNING: '" + value + "' is illegal value for " + IV_TYPE + + ". Using 'random' for the IV type."); + } return "random"; } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getHashAlgorithm() { return getESAPIProperty(HASH_ALGORITHM, "SHA-512"); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public int getHashIterations() { - return getESAPIProperty(HASH_ITERATIONS, 1024); + return getESAPIProperty(HASH_ITERATIONS, 1024); } /** * {@inheritDoc} */ - public String getKDFPseudoRandomFunction() { - return getESAPIProperty(KDF_PRF_ALG, "HmacSHA256"); // NSA recommended SHA2 or better. - } + public String getKDFPseudoRandomFunction() { + return getESAPIProperty(KDF_PRF_ALG, "HmacSHA256"); // NSA recommended SHA2 or better. + } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getCharacterEncoding() { return getESAPIProperty(CHARACTER_ENCODING, "UTF-8"); } /** - * {@inheritDoc} - */ - public boolean getAllowMultipleEncoding() { - return getESAPIProperty( ALLOW_MULTIPLE_ENCODING, false ); - } + * {@inheritDoc} + */ + public boolean getAllowMultipleEncoding() { + return getESAPIProperty( ALLOW_MULTIPLE_ENCODING, false ); + } /** - * {@inheritDoc} - */ - public boolean getAllowMixedEncoding() { - return getESAPIProperty( ALLOW_MIXED_ENCODING, false ); - } + * {@inheritDoc} + */ + public boolean getAllowMixedEncoding() { + return getESAPIProperty( ALLOW_MIXED_ENCODING, false ); + } /** - * {@inheritDoc} - */ - public List getDefaultCanonicalizationCodecs() { - List def = new ArrayList(); - def.add( "org.owasp.esapi.codecs.HTMLEntityCodec" ); - def.add( "org.owasp.esapi.codecs.PercentCodec" ); - def.add( "org.owasp.esapi.codecs.JavaScriptCodec" ); - return getESAPIProperty( CANONICALIZATION_CODECS, def ); - } + * {@inheritDoc} + */ + public List getDefaultCanonicalizationCodecs() { + List def = new ArrayList(); + def.add( "org.owasp.esapi.codecs.HTMLEntityCodec" ); + def.add( "org.owasp.esapi.codecs.PercentCodec" ); + def.add( "org.owasp.esapi.codecs.JavaScriptCodec" ); + return getESAPIProperty( CANONICALIZATION_CODECS, def ); + } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getDigitalSignatureAlgorithm() { return getESAPIProperty(DIGITAL_SIGNATURE_ALGORITHM, "SHAwithDSA"); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public int getDigitalSignatureKeyLength() { return getESAPIProperty(DIGITAL_SIGNATURE_KEY_LENGTH, 1024); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public String getRandomAlgorithm() { return getESAPIProperty(RANDOM_ALGORITHM, "SHA1PRNG"); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public int getAllowedLoginAttempts() { return getESAPIProperty(ALLOWED_LOGIN_ATTEMPTS, 5); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public int getMaxOldPasswordHashes() { return getESAPIProperty(MAX_OLD_PASSWORD_HASHES, 12); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public File getUploadDirectory() { - String dir = getESAPIProperty( UPLOAD_DIRECTORY, "UploadDir"); - return new File( dir ); + String dir = getESAPIProperty( UPLOAD_DIRECTORY, "UploadDir"); + return new File( dir ); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public File getUploadTempDirectory() { - String dir = getESAPIProperty(UPLOAD_TEMP_DIRECTORY, + String dir = getESAPIProperty(UPLOAD_TEMP_DIRECTORY, System.getProperty("java.io.tmpdir","UploadTempDir")); - return new File( dir ); + return new File( dir ); } /** - * {@inheritDoc} - */ - public boolean getDisableIntrusionDetection() { - String value = properties.getProperty( DISABLE_INTRUSION_DETECTION ); - if ("true".equalsIgnoreCase(value)) return true; - return false; // Default result - } + * {@inheritDoc} + */ + public boolean getDisableIntrusionDetection() { + String value = properties.getProperty( DISABLE_INTRUSION_DETECTION ); + if ("true".equalsIgnoreCase(value)) return true; + return false; // Default result + } /** - * {@inheritDoc} - */ - public Threshold getQuota(String eventName) { + * {@inheritDoc} + */ + public Threshold getQuota(String eventName) { int count = getESAPIProperty("IntrusionDetector." + eventName + ".count", 0); int interval = getESAPIProperty("IntrusionDetector." + eventName + ".interval", 0); List actions = new ArrayList(); @@ -987,247 +987,247 @@ public Threshold getQuota(String eventName) { actions = Arrays.asList(actionList); } if ( count > 0 && interval > 0 && actions.size() > 0 ) { - return new Threshold(eventName, count, interval, actions); + return new Threshold(eventName, count, interval, actions); } return null; } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public boolean getLogEncodingRequired() { - return getESAPIProperty( LOG_ENCODING_REQUIRED, false ); - } + return getESAPIProperty( LOG_ENCODING_REQUIRED, false ); + } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public boolean getLogApplicationName() { - return getESAPIProperty( LOG_APPLICATION_NAME, true ); - } + return getESAPIProperty( LOG_APPLICATION_NAME, true ); + } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public boolean getLogServerIP() { - return getESAPIProperty( LOG_SERVER_IP, true ); - } + return getESAPIProperty( LOG_SERVER_IP, true ); + } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public boolean getForceHttpOnlySession() { - return getESAPIProperty( FORCE_HTTPONLYSESSION, true ); + return getESAPIProperty( FORCE_HTTPONLYSESSION, true ); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public boolean getForceSecureSession() { - return getESAPIProperty( FORCE_SECURESESSION, true ); + return getESAPIProperty( FORCE_SECURESESSION, true ); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public boolean getForceHttpOnlyCookies() { - return getESAPIProperty( FORCE_HTTPONLYCOOKIES, true ); + return getESAPIProperty( FORCE_HTTPONLYCOOKIES, true ); } /** - * {@inheritDoc} - */ + * {@inheritDoc} + */ public boolean getForceSecureCookies() { - return getESAPIProperty( FORCE_SECURECOOKIES, true ); + return getESAPIProperty( FORCE_SECURECOOKIES, true ); } /** - * {@inheritDoc} - */ - public int getMaxHttpHeaderSize() { + * {@inheritDoc} + */ + public int getMaxHttpHeaderSize() { return getESAPIProperty( MAX_HTTP_HEADER_SIZE, 4096); - } + } /** - * {@inheritDoc} - */ - public String getResponseContentType() { + * {@inheritDoc} + */ + public String getResponseContentType() { return getESAPIProperty( RESPONSE_CONTENT_TYPE, "text/html; charset=UTF-8" ); } - /** - * {@inheritDoc} - */ - public String getHttpSessionIdName() { + /** + * {@inheritDoc} + */ + public String getHttpSessionIdName() { return getESAPIProperty( HTTP_SESSION_ID_NAME, "JSESSIONID" ); } - - /** - * {@inheritDoc} - */ + + /** + * {@inheritDoc} + */ public long getRememberTokenDuration() { int days = getESAPIProperty( REMEMBER_TOKEN_DURATION, 14 ); return (long) (1000 * 60 * 60 * 24 * days); } /** - * {@inheritDoc} - */ - public int getSessionIdleTimeoutLength() { + * {@inheritDoc} + */ + public int getSessionIdleTimeoutLength() { int minutes = getESAPIProperty( IDLE_TIMEOUT_DURATION, 20 ); return 1000 * 60 * minutes; - } + } - /** - * {@inheritDoc} - */ - public int getSessionAbsoluteTimeoutLength() { + /** + * {@inheritDoc} + */ + public int getSessionAbsoluteTimeoutLength() { int minutes = getESAPIProperty(ABSOLUTE_TIMEOUT_DURATION, 20 ); return 1000 * 60 * minutes; - } + } /** * getValidationPattern returns a single pattern based upon key * * @param key - * validation pattern name you'd like + * validation pattern name you'd like * @return - * if key exists, the associated validation pattern, null otherwise - */ + * if key exists, the associated validation pattern, null otherwise + */ public Pattern getValidationPattern( String key ) { - String value = getESAPIProperty( "Validator." + key, "" ); - // check cache - Pattern p = patternCache.get( value ); - if ( p != null ) return p; + String value = getESAPIProperty( "Validator." + key, "" ); + // check cache + Pattern p = patternCache.get( value ); + if ( p != null ) return p; - // compile a new pattern - if ( value == null || value.equals( "" ) ) return null; - try { - Pattern q = Pattern.compile(value); - patternCache.put( value, q ); - return q; - } catch ( PatternSyntaxException e ) { - logSpecial( "SecurityConfiguration for " + key + " not a valid regex in ESAPI.properties. Returning null", null ); - return null; - } + // compile a new pattern + if ( value == null || value.equals( "" ) ) return null; + try { + Pattern q = Pattern.compile(value); + patternCache.put( value, q ); + return q; + } catch ( PatternSyntaxException e ) { + logSpecial( "SecurityConfiguration for " + key + " not a valid regex in ESAPI.properties. Returning null", null ); + return null; + } } /** * getWorkingDirectory returns the default directory where processes will be executed * by the Executor. */ - public File getWorkingDirectory() { - String dir = getESAPIProperty( WORKING_DIRECTORY, System.getProperty( "user.dir") ); - if ( dir != null ) { - return new File( dir ); - } - return null; - } - - /** - * {@inheritDoc} - */ - public String getPreferredJCEProvider() { - return properties.getProperty(PREFERRED_JCE_PROVIDER); // No default! - } - - /** - * {@inheritDoc} - */ - public List getCombinedCipherModes() - { - List empty = new ArrayList(); // Default is empty list - return getESAPIProperty(COMBINED_CIPHER_MODES, empty); - } - - /** - * {@inheritDoc} - */ - public List getAdditionalAllowedCipherModes() - { - List empty = new ArrayList(); // Default is empty list - return getESAPIProperty(ADDITIONAL_ALLOWED_CIPHER_MODES, empty); - } - - /** - * {@inheritDoc} - */ - public boolean getLenientDatesAccepted() { - return getESAPIProperty( ACCEPT_LENIENT_DATES, false); - } - - protected String getESAPIProperty( String key, String def ) { - String value = properties.getProperty(key); - if ( value == null ) { - logSpecial( "SecurityConfiguration for " + key + " not found in ESAPI.properties. Using default: " + def, null ); - return def; - } - return value; - } - - protected boolean getESAPIProperty( String key, boolean def ) { - String property = properties.getProperty(key); - if ( property == null ) { - logSpecial( "SecurityConfiguration for " + key + " not found in ESAPI.properties. Using default: " + def, null ); - return def; - } - if ( property.equalsIgnoreCase("true") || property.equalsIgnoreCase("yes" ) ) { - return true; - } - if ( property.equalsIgnoreCase("false") || property.equalsIgnoreCase( "no" ) ) { - return false; - } - logSpecial( "SecurityConfiguration for " + key + " not either \"true\" or \"false\" in ESAPI.properties. Using default: " + def, null ); - return def; - } - - protected byte[] getESAPIPropertyEncoded( String key, byte[] def ) { - String property = properties.getProperty(key); - if ( property == null ) { - logSpecial( "SecurityConfiguration for " + key + " not found in ESAPI.properties. Using default: " + def, null ); - return def; - } + public File getWorkingDirectory() { + String dir = getESAPIProperty( WORKING_DIRECTORY, System.getProperty( "user.dir") ); + if ( dir != null ) { + return new File( dir ); + } + return null; + } + + /** + * {@inheritDoc} + */ + public String getPreferredJCEProvider() { + return properties.getProperty(PREFERRED_JCE_PROVIDER); // No default! + } + + /** + * {@inheritDoc} + */ + public List getCombinedCipherModes() + { + List empty = new ArrayList(); // Default is empty list + return getESAPIProperty(COMBINED_CIPHER_MODES, empty); + } + + /** + * {@inheritDoc} + */ + public List getAdditionalAllowedCipherModes() + { + List empty = new ArrayList(); // Default is empty list + return getESAPIProperty(ADDITIONAL_ALLOWED_CIPHER_MODES, empty); + } + + /** + * {@inheritDoc} + */ + public boolean getLenientDatesAccepted() { + return getESAPIProperty( ACCEPT_LENIENT_DATES, false); + } + + protected String getESAPIProperty( String key, String def ) { + String value = properties.getProperty(key); + if ( value == null ) { + logSpecial( "SecurityConfiguration for " + key + " not found in ESAPI.properties. Using default: " + def, null ); + return def; + } + return value; + } + + protected boolean getESAPIProperty( String key, boolean def ) { + String property = properties.getProperty(key); + if ( property == null ) { + logSpecial( "SecurityConfiguration for " + key + " not found in ESAPI.properties. Using default: " + def, null ); + return def; + } + if ( property.equalsIgnoreCase("true") || property.equalsIgnoreCase("yes" ) ) { + return true; + } + if ( property.equalsIgnoreCase("false") || property.equalsIgnoreCase( "no" ) ) { + return false; + } + logSpecial( "SecurityConfiguration for " + key + " not either \"true\" or \"false\" in ESAPI.properties. Using default: " + def, null ); + return def; + } + + protected byte[] getESAPIPropertyEncoded( String key, byte[] def ) { + String property = properties.getProperty(key); + if ( property == null ) { + logSpecial( "SecurityConfiguration for " + key + " not found in ESAPI.properties. Using default: " + def, null ); + return def; + } try { return ESAPI.encoder().decodeFromBase64(property); } catch( IOException e ) { - logSpecial( "SecurityConfiguration for " + key + " not properly Base64 encoded in ESAPI.properties. Using default: " + def, null ); + logSpecial( "SecurityConfiguration for " + key + " not properly Base64 encoded in ESAPI.properties. Using default: " + def, null ); return null; } - } - - protected int getESAPIProperty( String key, int def ) { - String property = properties.getProperty(key); - if ( property == null ) { - logSpecial( "SecurityConfiguration for " + key + " not found in ESAPI.properties. Using default: " + def, null ); - return def; - } - try { + } + + protected int getESAPIProperty( String key, int def ) { + String property = properties.getProperty(key); + if ( property == null ) { + logSpecial( "SecurityConfiguration for " + key + " not found in ESAPI.properties. Using default: " + def, null ); + return def; + } + try { return Integer.parseInt( property ); - } catch( NumberFormatException e ) { - logSpecial( "SecurityConfiguration for " + key + " not an integer in ESAPI.properties. Using default: " + def, null ); - return def; - } - } + } catch( NumberFormatException e ) { + logSpecial( "SecurityConfiguration for " + key + " not an integer in ESAPI.properties. Using default: " + def, null ); + return def; + } + } - /** + /** * Returns a {@code List} representing the parsed, comma-separated property. * - * @param key The specified property name - * @param def A default value for the property name to return if the property - * is not set. - * @return A list of strings. - */ - protected List getESAPIProperty( String key, List def ) { - String property = properties.getProperty( key ); - if ( property == null ) { - logSpecial( "SecurityConfiguration for " + key + " not found in ESAPI.properties. Using default: " + def, null ); - return def; - } - String[] parts = property.split(","); - return Arrays.asList( parts ); - } + * @param key The specified property name + * @param def A default value for the property name to return if the property + * is not set. + * @return A list of strings. + */ + protected List getESAPIProperty( String key, List def ) { + String property = properties.getProperty( key ); + if ( property == null ) { + logSpecial( "SecurityConfiguration for " + key + " not found in ESAPI.properties. Using default: " + def, null ); + return def; + } + String[] parts = property.split(","); + return Arrays.asList( parts ); + } /** * {@inheritDoc} @@ -1326,29 +1326,29 @@ public String getStringProp(String propertyName) throws ConfigurationException { protected boolean shouldPrintProperties() { return getESAPIProperty(PRINT_PROPERTIES_WHEN_LOADED, false); - } + } protected Properties getESAPIProperties() { return properties; } public enum DefaultSearchPath { - - RESOURCE_DIRECTORY("resourceDirectory/"), - SRC_MAIN_RESOURCES("src/main/resources/"), - ROOT(""), - DOT_ESAPI(".esapi/"), - ESAPI("esapi/"), - RESOURCES("resources/"); - - private final String path; - - private DefaultSearchPath(String s){ - this.path = s; - } - - public String value(){ - return path; - } + + RESOURCE_DIRECTORY("resourceDirectory/"), + SRC_MAIN_RESOURCES("src/main/resources/"), + ROOT(""), + DOT_ESAPI(".esapi/"), + ESAPI("esapi/"), + RESOURCES("resources/"); + + private final String path; + + private DefaultSearchPath(String s){ + this.path = s; + } + + public String value(){ + return path; + } } } diff --git a/src/main/java/org/owasp/esapi/reference/DefaultUser.java b/src/main/java/org/owasp/esapi/reference/DefaultUser.java index a0553cec3..c9d448c2b 100644 --- a/src/main/java/org/owasp/esapi/reference/DefaultUser.java +++ b/src/main/java/org/owasp/esapi/reference/DefaultUser.java @@ -40,544 +40,544 @@ */ public class DefaultUser implements User, Serializable { - /** The Constant serialVersionUID. */ - private static final long serialVersionUID = 1L; - - /** The idle timeout length specified in the ESAPI config file. */ - private static final int IDLE_TIMEOUT_LENGTH = ESAPI.securityConfiguration().getSessionIdleTimeoutLength(); - - /** The absolute timeout length specified in the ESAPI config file. */ - private static final int ABSOLUTE_TIMEOUT_LENGTH = ESAPI.securityConfiguration().getSessionAbsoluteTimeoutLength(); - - /** The logger used by the class. */ - private transient final Logger logger = ESAPI.getLogger("DefaultUser"); + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 1L; + + /** The idle timeout length specified in the ESAPI config file. */ + private static final int IDLE_TIMEOUT_LENGTH = ESAPI.securityConfiguration().getSessionIdleTimeoutLength(); + + /** The absolute timeout length specified in the ESAPI config file. */ + private static final int ABSOLUTE_TIMEOUT_LENGTH = ESAPI.securityConfiguration().getSessionAbsoluteTimeoutLength(); - /** This user's account id. */ - long accountId = 0; + /** The logger used by the class. */ + private transient final Logger logger = ESAPI.getLogger("DefaultUser"); + + /** This user's account id. */ + long accountId = 0; - /** This user's account name. */ - private String accountName = ""; + /** This user's account name. */ + private String accountName = ""; - /** This user's screen name (account name alias). */ - private String screenName = ""; + /** This user's screen name (account name alias). */ + private String screenName = ""; - /** This user's CSRF token. */ - private String csrfToken = resetCSRFToken(); + /** This user's CSRF token. */ + private String csrfToken = resetCSRFToken(); - /** This user's assigned roles. */ - private Set roles = new HashSet(); + /** This user's assigned roles. */ + private Set roles = new HashSet(); - /** Whether this user's account is locked. */ - private boolean locked = false; + /** Whether this user's account is locked. */ + private boolean locked = false; - /** Whether this user is logged in. */ - private boolean loggedIn = true; + /** Whether this user is logged in. */ + private boolean loggedIn = true; /** Whether this user's account is enabled. */ - private boolean enabled = false; + private boolean enabled = false; /** The last host address used by this user. */ private String lastHostAddress; - /** The last password change time for this user. */ - private Date lastPasswordChangeTime = new Date(0); - - /** The last login time for this user. */ - private Date lastLoginTime = new Date(0); - - /** The last failed login time for this user. */ - private Date lastFailedLoginTime = new Date(0); - - /** The expiration date/time for this user's account. */ - private Date expirationTime = new Date(Long.MAX_VALUE); - - /** The sessions this user is associated with */ - private transient Set sessions = new HashSet(); - - /** The event map for this User */ - private transient HashMap eventMap = new HashMap(); - - /* A flag to indicate that the password must be changed before the account can be used. */ - // private boolean requiresPasswordChange = true; - - /** The failed login count for this user's account. */ - private int failedLoginCount = 0; - - /** This user's Locale. */ - private Locale locale; + /** The last password change time for this user. */ + private Date lastPasswordChangeTime = new Date(0); + + /** The last login time for this user. */ + private Date lastLoginTime = new Date(0); + + /** The last failed login time for this user. */ + private Date lastFailedLoginTime = new Date(0); + + /** The expiration date/time for this user's account. */ + private Date expirationTime = new Date(Long.MAX_VALUE); + + /** The sessions this user is associated with */ + private transient Set sessions = new HashSet(); + + /** The event map for this User */ + private transient HashMap eventMap = new HashMap(); + + /* A flag to indicate that the password must be changed before the account can be used. */ + // private boolean requiresPasswordChange = true; + + /** The failed login count for this user's account. */ + private int failedLoginCount = 0; + + /** This user's Locale. */ + private Locale locale; private static final int MAX_ROLE_LENGTH = 250; - /** - * Instantiates a new user. - * - * @param accountName - * The name of this user's account. - */ - public DefaultUser(String accountName) { - this.accountName = accountName.toLowerCase(); - while( true ) { - long id = Math.abs( ESAPI.randomizer().getRandomLong() ); - if ( ESAPI.authenticator().getUser( id ) == null && id != 0 ) { - this.accountId = id; - break; - } - } - } - - /** - * {@inheritDoc} - */ - public void addRole(String role) throws AuthenticationException { - String roleName = role.toLowerCase(); - if ( ESAPI.validator().isValidInput("addRole", roleName, "RoleName", MAX_ROLE_LENGTH, false) ) { - roles.add(roleName); - logger.info(Logger.SECURITY_SUCCESS, "Role " + roleName + " added to " + getAccountName() ); - } else { - throw new AuthenticationAccountsException( "Add role failed", "Attempt to add invalid role " + roleName + " to " + getAccountName() ); - } - } - - /** - * {@inheritDoc} - */ - public void addRoles(Set newRoles) throws AuthenticationException { + /** + * Instantiates a new user. + * + * @param accountName + * The name of this user's account. + */ + public DefaultUser(String accountName) { + this.accountName = accountName.toLowerCase(); + while( true ) { + long id = Math.abs( ESAPI.randomizer().getRandomLong() ); + if ( ESAPI.authenticator().getUser( id ) == null && id != 0 ) { + this.accountId = id; + break; + } + } + } + + /** + * {@inheritDoc} + */ + public void addRole(String role) throws AuthenticationException { + String roleName = role.toLowerCase(); + if ( ESAPI.validator().isValidInput("addRole", roleName, "RoleName", MAX_ROLE_LENGTH, false) ) { + roles.add(roleName); + logger.info(Logger.SECURITY_SUCCESS, "Role " + roleName + " added to " + getAccountName() ); + } else { + throw new AuthenticationAccountsException( "Add role failed", "Attempt to add invalid role " + roleName + " to " + getAccountName() ); + } + } + + /** + * {@inheritDoc} + */ + public void addRoles(Set newRoles) throws AuthenticationException { for (String newRole : newRoles) { addRole(newRole); - } - } - - /** - * {@inheritDoc} - */ - public void changePassword(String oldPassword, String newPassword1, String newPassword2) throws AuthenticationException, EncryptionException { - ESAPI.authenticator().changePassword(this, oldPassword, newPassword1, newPassword2); - } - - /** - * {@inheritDoc} - */ - public void disable() { - enabled = false; - logger.info( Logger.SECURITY_SUCCESS, "Account disabled: " + getAccountName() ); - } - - /** - * {@inheritDoc} - */ - public void enable() { - this.enabled = true; - logger.info( Logger.SECURITY_SUCCESS, "Account enabled: " + getAccountName() ); - } - - /** - * {@inheritDoc} - */ + } + } + + /** + * {@inheritDoc} + */ + public void changePassword(String oldPassword, String newPassword1, String newPassword2) throws AuthenticationException, EncryptionException { + ESAPI.authenticator().changePassword(this, oldPassword, newPassword1, newPassword2); + } + + /** + * {@inheritDoc} + */ + public void disable() { + enabled = false; + logger.info( Logger.SECURITY_SUCCESS, "Account disabled: " + getAccountName() ); + } + + /** + * {@inheritDoc} + */ + public void enable() { + this.enabled = true; + logger.info( Logger.SECURITY_SUCCESS, "Account enabled: " + getAccountName() ); + } + + /** + * {@inheritDoc} + */ public long getAccountId() { return accountId; } - /** - * {@inheritDoc} - */ - public String getAccountName() { - return accountName; - } - - /** - * {@inheritDoc} - */ - public String getCSRFToken() { - return csrfToken; - } - - /** - * {@inheritDoc} - */ - public Date getExpirationTime() { - return (Date)expirationTime.clone(); - } - - /** - * {@inheritDoc} - */ - public int getFailedLoginCount() { - return failedLoginCount; - } - - /** - * Set the failed login count - * - * @param count - * the number of failed logins - */ - void setFailedLoginCount(int count) { - failedLoginCount = count; - } - - /** - * {@inheritDoc} - */ - public Date getLastFailedLoginTime() { - return (Date)lastFailedLoginTime.clone(); - } - - /** - * {@inheritDoc} - */ - public String getLastHostAddress() { - if ( lastHostAddress == null ) { - return "unknown"; - } + /** + * {@inheritDoc} + */ + public String getAccountName() { + return accountName; + } + + /** + * {@inheritDoc} + */ + public String getCSRFToken() { + return csrfToken; + } + + /** + * {@inheritDoc} + */ + public Date getExpirationTime() { + return (Date)expirationTime.clone(); + } + + /** + * {@inheritDoc} + */ + public int getFailedLoginCount() { + return failedLoginCount; + } + + /** + * Set the failed login count + * + * @param count + * the number of failed logins + */ + void setFailedLoginCount(int count) { + failedLoginCount = count; + } + + /** + * {@inheritDoc} + */ + public Date getLastFailedLoginTime() { + return (Date)lastFailedLoginTime.clone(); + } + + /** + * {@inheritDoc} + */ + public String getLastHostAddress() { + if ( lastHostAddress == null ) { + return "unknown"; + } return lastHostAddress; } - /** - * {@inheritDoc} - */ - public Date getLastLoginTime() { - return (Date)lastLoginTime.clone(); - } - - /** - * {@inheritDoc} - */ - public Date getLastPasswordChangeTime() { - return (Date)lastPasswordChangeTime.clone(); - } - - /** - * {@inheritDoc} - */ - public String getName() { - return this.getAccountName(); - } - - /** - * {@inheritDoc} - */ - public Set getRoles() { - return Collections.unmodifiableSet(roles); - } - - /** - * {@inheritDoc} - */ - public String getScreenName() { - return screenName; - } - - /** - * {@inheritDoc} - */ + /** + * {@inheritDoc} + */ + public Date getLastLoginTime() { + return (Date)lastLoginTime.clone(); + } + + /** + * {@inheritDoc} + */ + public Date getLastPasswordChangeTime() { + return (Date)lastPasswordChangeTime.clone(); + } + + /** + * {@inheritDoc} + */ + public String getName() { + return this.getAccountName(); + } + + /** + * {@inheritDoc} + */ + public Set getRoles() { + return Collections.unmodifiableSet(roles); + } + + /** + * {@inheritDoc} + */ + public String getScreenName() { + return screenName; + } + + /** + * {@inheritDoc} + */ public void addSession( HttpSession s ) { sessions.add( s ); } - /** - * {@inheritDoc} - */ + /** + * {@inheritDoc} + */ public void removeSession( HttpSession s ) { sessions.remove( s ); } - /** - * {@inheritDoc} - */ - public Set getSessions() { - return sessions; - } - - /** - * {@inheritDoc} - */ - public void incrementFailedLoginCount() { - failedLoginCount++; - } - - /** - * {@inheritDoc} - */ - public boolean isAnonymous() { - // User cannot be anonymous, since we have a special User.ANONYMOUS instance - // for the anonymous user - return false; - } - - /** - * {@inheritDoc} - */ - public boolean isEnabled() { - return enabled; - } - - /** - * {@inheritDoc} - */ - public boolean isExpired() { - return getExpirationTime().before( new Date() ); - - // If expiration should happen automatically or based on lastPasswordChangeTime? - // long from = lastPasswordChangeTime.getTime(); - // long to = new Date().getTime(); - // double difference = to - from; - // long days = Math.round((difference / (1000 * 60 * 60 * 24))); - // return days > 60; - } - - /** - * {@inheritDoc} - */ - public boolean isInRole(String role) { - return roles.contains(role.toLowerCase()); - } - - /** - * {@inheritDoc} - */ - public boolean isLocked() { - return locked; - } - - /** - * {@inheritDoc} - */ - public boolean isLoggedIn() { - return loggedIn; - } - - /** - * {@inheritDoc} - */ - public boolean isSessionAbsoluteTimeout() { - HttpSession session = ESAPI.httpUtilities().getCurrentRequest().getSession(false); - if ( session == null ) return true; - Date deadline = new Date( session.getCreationTime() + ABSOLUTE_TIMEOUT_LENGTH); - Date now = new Date(); - return now.after(deadline); - } - - /** - * {@inheritDoc} - */ - public boolean isSessionTimeout() { - HttpSession session = ESAPI.httpUtilities().getCurrentRequest().getSession(false); - if ( session == null ) return true; - Date deadline = new Date( session.getLastAccessedTime() + IDLE_TIMEOUT_LENGTH); - Date now = new Date(); - return now.after(deadline); - } - - /** - * {@inheritDoc} - */ - public void lock() { - this.locked = true; - logger.info(Logger.SECURITY_SUCCESS, "Account locked: " + getAccountName() ); - } - - /** - * {@inheritDoc} - */ - public void loginWithPassword(String password) throws AuthenticationException { - if ( password == null || password.equals("") ) { - setLastFailedLoginTime(new Date()); - incrementFailedLoginCount(); - throw new AuthenticationLoginException( "Login failed", "Missing password: " + accountName ); - } - - // don't let disabled users log in - if ( !isEnabled() ) { - setLastFailedLoginTime(new Date()); - incrementFailedLoginCount(); - throw new AuthenticationLoginException("Login failed", "Disabled user attempt to login: " + accountName ); - } - - // don't let locked users log in - if ( isLocked() ) { - setLastFailedLoginTime(new Date()); - incrementFailedLoginCount(); - throw new AuthenticationLoginException("Login failed", "Locked user attempt to login: " + accountName ); - } - - // don't let expired users log in - if ( isExpired() ) { - setLastFailedLoginTime(new Date()); - incrementFailedLoginCount(); - throw new AuthenticationLoginException("Login failed", "Expired user attempt to login: " + accountName ); - } - - logout(); - - if ( verifyPassword( password ) ) { - loggedIn = true; - ESAPI.httpUtilities().changeSessionIdentifier( ESAPI.currentRequest() ); - ESAPI.authenticator().setCurrentUser(this); - setLastLoginTime(new Date()); + /** + * {@inheritDoc} + */ + public Set getSessions() { + return sessions; + } + + /** + * {@inheritDoc} + */ + public void incrementFailedLoginCount() { + failedLoginCount++; + } + + /** + * {@inheritDoc} + */ + public boolean isAnonymous() { + // User cannot be anonymous, since we have a special User.ANONYMOUS instance + // for the anonymous user + return false; + } + + /** + * {@inheritDoc} + */ + public boolean isEnabled() { + return enabled; + } + + /** + * {@inheritDoc} + */ + public boolean isExpired() { + return getExpirationTime().before( new Date() ); + + // If expiration should happen automatically or based on lastPasswordChangeTime? + // long from = lastPasswordChangeTime.getTime(); + // long to = new Date().getTime(); + // double difference = to - from; + // long days = Math.round((difference / (1000 * 60 * 60 * 24))); + // return days > 60; + } + + /** + * {@inheritDoc} + */ + public boolean isInRole(String role) { + return roles.contains(role.toLowerCase()); + } + + /** + * {@inheritDoc} + */ + public boolean isLocked() { + return locked; + } + + /** + * {@inheritDoc} + */ + public boolean isLoggedIn() { + return loggedIn; + } + + /** + * {@inheritDoc} + */ + public boolean isSessionAbsoluteTimeout() { + HttpSession session = ESAPI.httpUtilities().getCurrentRequest().getSession(false); + if ( session == null ) return true; + Date deadline = new Date( session.getCreationTime() + ABSOLUTE_TIMEOUT_LENGTH); + Date now = new Date(); + return now.after(deadline); + } + + /** + * {@inheritDoc} + */ + public boolean isSessionTimeout() { + HttpSession session = ESAPI.httpUtilities().getCurrentRequest().getSession(false); + if ( session == null ) return true; + Date deadline = new Date( session.getLastAccessedTime() + IDLE_TIMEOUT_LENGTH); + Date now = new Date(); + return now.after(deadline); + } + + /** + * {@inheritDoc} + */ + public void lock() { + this.locked = true; + logger.info(Logger.SECURITY_SUCCESS, "Account locked: " + getAccountName() ); + } + + /** + * {@inheritDoc} + */ + public void loginWithPassword(String password) throws AuthenticationException { + if ( password == null || password.equals("") ) { + setLastFailedLoginTime(new Date()); + incrementFailedLoginCount(); + throw new AuthenticationLoginException( "Login failed", "Missing password: " + accountName ); + } + + // don't let disabled users log in + if ( !isEnabled() ) { + setLastFailedLoginTime(new Date()); + incrementFailedLoginCount(); + throw new AuthenticationLoginException("Login failed", "Disabled user attempt to login: " + accountName ); + } + + // don't let locked users log in + if ( isLocked() ) { + setLastFailedLoginTime(new Date()); + incrementFailedLoginCount(); + throw new AuthenticationLoginException("Login failed", "Locked user attempt to login: " + accountName ); + } + + // don't let expired users log in + if ( isExpired() ) { + setLastFailedLoginTime(new Date()); + incrementFailedLoginCount(); + throw new AuthenticationLoginException("Login failed", "Expired user attempt to login: " + accountName ); + } + + logout(); + + if ( verifyPassword( password ) ) { + loggedIn = true; + ESAPI.httpUtilities().changeSessionIdentifier( ESAPI.currentRequest() ); + ESAPI.authenticator().setCurrentUser(this); + setLastLoginTime(new Date()); setLastHostAddress( ESAPI.httpUtilities().getCurrentRequest().getRemoteAddr() ); - logger.trace(Logger.SECURITY_SUCCESS, "User logged in: " + accountName ); - } else { - loggedIn = false; - setLastFailedLoginTime(new Date()); - incrementFailedLoginCount(); - if (getFailedLoginCount() >= ESAPI.securityConfiguration().getAllowedLoginAttempts()) { - lock(); - } - throw new AuthenticationLoginException("Login failed", "Incorrect password provided for " + getAccountName() ); - } - } + logger.trace(Logger.SECURITY_SUCCESS, "User logged in: " + accountName ); + } else { + loggedIn = false; + setLastFailedLoginTime(new Date()); + incrementFailedLoginCount(); + if (getFailedLoginCount() >= ESAPI.securityConfiguration().getAllowedLoginAttempts()) { + lock(); + } + throw new AuthenticationLoginException("Login failed", "Incorrect password provided for " + getAccountName() ); + } + } - /** - * {@inheritDoc} - */ - public void logout() { - ESAPI.httpUtilities().killCookie( ESAPI.currentRequest(), ESAPI.currentResponse(), HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME ); - - HttpSession session = ESAPI.currentRequest().getSession(false); - if (session != null) { + /** + * {@inheritDoc} + */ + public void logout() { + ESAPI.httpUtilities().killCookie( ESAPI.currentRequest(), ESAPI.currentResponse(), HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME ); + + HttpSession session = ESAPI.currentRequest().getSession(false); + if (session != null) { removeSession(session); - session.invalidate(); - } - ESAPI.httpUtilities().killCookie(ESAPI.currentRequest(), ESAPI.currentResponse(), ESAPI.securityConfiguration().getHttpSessionIdName()); - loggedIn = false; - logger.info(Logger.SECURITY_SUCCESS, "Logout successful" ); - ESAPI.authenticator().setCurrentUser(User.ANONYMOUS); - } - - /** - * {@inheritDoc} - */ - public void removeRole(String role) { - roles.remove(role.toLowerCase()); - logger.trace(Logger.SECURITY_SUCCESS, "Role " + role + " removed from " + getAccountName() ); - } - - /** - * {@inheritDoc} - * - * In this implementation, we have chosen to use a random token that is - * stored in the User object. Note that it is possible to avoid the use of - * server side state by using either the hash of the users's session id or - * an encrypted token that includes a timestamp and the user's IP address. - * user's IP address. A relatively short 8 character string has been chosen - * because this token will appear in all links and forms. - * - * @return the string - */ - public String resetCSRFToken() { - // user.csrfToken = ESAPI.encryptor().hash( session.getId(),user.name ); - // user.csrfToken = ESAPI.encryptor().encrypt( address + ":" + ESAPI.encryptor().getTimeStamp(); - csrfToken = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS); - return csrfToken; - } - - /** - * Sets the account id for this user's account. - */ - private void setAccountId(long accountId) { - this.accountId = accountId; - } - - - /** - * {@inheritDoc} - */ - public void setAccountName(String accountName) { - String old = getAccountName(); - this.accountName = accountName.toLowerCase(); - if (old != null) { - if ( old.equals( "" ) ) { - old = "[nothing]"; - } - logger.info(Logger.SECURITY_SUCCESS, "Account name changed from " + old + " to " + getAccountName() ); - } - } - - /** - * {@inheritDoc} - */ - public void setExpirationTime(Date expirationTime) { - this.expirationTime = new Date( expirationTime.getTime() ); - logger.info(Logger.SECURITY_SUCCESS, "Account expiration time set to " + expirationTime + " for " + getAccountName() ); - } - - /** - * {@inheritDoc} - */ - public void setLastFailedLoginTime(Date lastFailedLoginTime) { - this.lastFailedLoginTime = lastFailedLoginTime; - logger.info(Logger.SECURITY_SUCCESS, "Set last failed login time to " + lastFailedLoginTime + " for " + getAccountName() ); - } - - /** - * {@inheritDoc} - */ - public void setLastHostAddress(String remoteHost) throws AuthenticationHostException + session.invalidate(); + } + ESAPI.httpUtilities().killCookie(ESAPI.currentRequest(), ESAPI.currentResponse(), ESAPI.securityConfiguration().getHttpSessionIdName()); + loggedIn = false; + logger.info(Logger.SECURITY_SUCCESS, "Logout successful" ); + ESAPI.authenticator().setCurrentUser(User.ANONYMOUS); + } + + /** + * {@inheritDoc} + */ + public void removeRole(String role) { + roles.remove(role.toLowerCase()); + logger.trace(Logger.SECURITY_SUCCESS, "Role " + role + " removed from " + getAccountName() ); + } + + /** + * {@inheritDoc} + * + * In this implementation, we have chosen to use a random token that is + * stored in the User object. Note that it is possible to avoid the use of + * server side state by using either the hash of the users's session id or + * an encrypted token that includes a timestamp and the user's IP address. + * user's IP address. A relatively short 8 character string has been chosen + * because this token will appear in all links and forms. + * + * @return the string + */ + public String resetCSRFToken() { + // user.csrfToken = ESAPI.encryptor().hash( session.getId(),user.name ); + // user.csrfToken = ESAPI.encryptor().encrypt( address + ":" + ESAPI.encryptor().getTimeStamp(); + csrfToken = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS); + return csrfToken; + } + + /** + * Sets the account id for this user's account. + */ + private void setAccountId(long accountId) { + this.accountId = accountId; + } + + + /** + * {@inheritDoc} + */ + public void setAccountName(String accountName) { + String old = getAccountName(); + this.accountName = accountName.toLowerCase(); + if (old != null) { + if ( old.equals( "" ) ) { + old = "[nothing]"; + } + logger.info(Logger.SECURITY_SUCCESS, "Account name changed from " + old + " to " + getAccountName() ); + } + } + + /** + * {@inheritDoc} + */ + public void setExpirationTime(Date expirationTime) { + this.expirationTime = new Date( expirationTime.getTime() ); + logger.info(Logger.SECURITY_SUCCESS, "Account expiration time set to " + expirationTime + " for " + getAccountName() ); + } + + /** + * {@inheritDoc} + */ + public void setLastFailedLoginTime(Date lastFailedLoginTime) { + this.lastFailedLoginTime = lastFailedLoginTime; + logger.info(Logger.SECURITY_SUCCESS, "Set last failed login time to " + lastFailedLoginTime + " for " + getAccountName() ); + } + + /** + * {@inheritDoc} + */ + public void setLastHostAddress(String remoteHost) throws AuthenticationHostException { - if ( lastHostAddress != null && !lastHostAddress.equals(remoteHost)) { - // returning remote address not remote hostname to prevent DNS lookup - throw new AuthenticationHostException("Host change", "User session just jumped from " + lastHostAddress + " to " + remoteHost ); - } - lastHostAddress = remoteHost; - } - - /** - * {@inheritDoc} - */ - public void setLastLoginTime(Date lastLoginTime) { - this.lastLoginTime = lastLoginTime; - logger.info(Logger.SECURITY_SUCCESS, "Set last successful login time to " + lastLoginTime + " for " + getAccountName() ); - } - - /** - * {@inheritDoc} - */ - public void setLastPasswordChangeTime(Date lastPasswordChangeTime) { - this.lastPasswordChangeTime = lastPasswordChangeTime; - logger.info(Logger.SECURITY_SUCCESS, "Set last password change time to " + lastPasswordChangeTime + " for " + getAccountName() ); - } - - /** - * {@inheritDoc} - */ - public void setRoles(Set roles) throws AuthenticationException { - this.roles = new HashSet(); - addRoles(roles); - logger.info(Logger.SECURITY_SUCCESS, "Adding roles " + roles + " to " + getAccountName() ); - } - - /** - * {@inheritDoc} - */ - public void setScreenName(String screenName) { - this.screenName = screenName; - logger.info(Logger.SECURITY_SUCCESS, "ScreenName changed to " + screenName + " for " + getAccountName() ); - } - - /** - * {@inheritDoc} - */ - public String toString() { - return "USER:" + accountName; - } - - /** - * {@inheritDoc} - */ - public void unlock() { - this.locked = false; - this.failedLoginCount = 0; - logger.info( Logger.SECURITY_SUCCESS, "Account unlocked: " + getAccountName() ); - } - - /** - * {@inheritDoc} - */ - public boolean verifyPassword(String password) { - return ESAPI.authenticator().verifyPassword(this, password); - } + if ( lastHostAddress != null && !lastHostAddress.equals(remoteHost)) { + // returning remote address not remote hostname to prevent DNS lookup + throw new AuthenticationHostException("Host change", "User session just jumped from " + lastHostAddress + " to " + remoteHost ); + } + lastHostAddress = remoteHost; + } + + /** + * {@inheritDoc} + */ + public void setLastLoginTime(Date lastLoginTime) { + this.lastLoginTime = lastLoginTime; + logger.info(Logger.SECURITY_SUCCESS, "Set last successful login time to " + lastLoginTime + " for " + getAccountName() ); + } + + /** + * {@inheritDoc} + */ + public void setLastPasswordChangeTime(Date lastPasswordChangeTime) { + this.lastPasswordChangeTime = lastPasswordChangeTime; + logger.info(Logger.SECURITY_SUCCESS, "Set last password change time to " + lastPasswordChangeTime + " for " + getAccountName() ); + } + + /** + * {@inheritDoc} + */ + public void setRoles(Set roles) throws AuthenticationException { + this.roles = new HashSet(); + addRoles(roles); + logger.info(Logger.SECURITY_SUCCESS, "Adding roles " + roles + " to " + getAccountName() ); + } + + /** + * {@inheritDoc} + */ + public void setScreenName(String screenName) { + this.screenName = screenName; + logger.info(Logger.SECURITY_SUCCESS, "ScreenName changed to " + screenName + " for " + getAccountName() ); + } + + /** + * {@inheritDoc} + */ + public String toString() { + return "USER:" + accountName; + } + + /** + * {@inheritDoc} + */ + public void unlock() { + this.locked = false; + this.failedLoginCount = 0; + logger.info( Logger.SECURITY_SUCCESS, "Account unlocked: " + getAccountName() ); + } + + /** + * {@inheritDoc} + */ + public boolean verifyPassword(String password) { + return ESAPI.authenticator().verifyPassword(this, password); + } /** * Override clone and make final to prevent duplicate user objects. @@ -585,24 +585,24 @@ public boolean verifyPassword(String password) { * @throws java.lang.CloneNotSupportedException */ public final Object clone() throws java.lang.CloneNotSupportedException { - throw new java.lang.CloneNotSupportedException(); - } - /** - * @return the locale - */ - public Locale getLocale() { - return locale; - } - - /** - * @param locale the locale to set - */ - public void setLocale(Locale locale) { - this.locale = locale; - } + throw new java.lang.CloneNotSupportedException(); + } + /** + * @return the locale + */ + public Locale getLocale() { + return locale; + } + + /** + * @param locale the locale to set + */ + public void setLocale(Locale locale) { + this.locale = locale; + } public HashMap getEventMap() { - return eventMap; + return eventMap; } } diff --git a/src/main/java/org/owasp/esapi/reference/DefaultValidator.java b/src/main/java/org/owasp/esapi/reference/DefaultValidator.java index 0699a5287..980ef7467 100644 --- a/src/main/java/org/owasp/esapi/reference/DefaultValidator.java +++ b/src/main/java/org/owasp/esapi/reference/DefaultValidator.java @@ -67,7 +67,7 @@ * @see org.owasp.esapi.Validator */ public class DefaultValidator implements org.owasp.esapi.Validator { - private static Logger logger = ESAPI.log(); + private static Logger logger = ESAPI.log(); private static volatile Validator instance = null; public static Validator getInstance() { @@ -81,1182 +81,1182 @@ public static Validator getInstance() { return instance; } - /** A map of validation rules */ - private Map rules = new HashMap(); + /** A map of validation rules */ + private Map rules = new HashMap(); - /** The encoder to use for canonicalization */ - private Encoder encoder = null; + /** The encoder to use for canonicalization */ + private Encoder encoder = null; - /** The encoder to use for file system */ - private static Validator fileValidator = null; + /** The encoder to use for file system */ + private static Validator fileValidator = null; - /** Initialize file validator with an appropriate set of codecs */ - static { - List list = new ArrayList(); - list.add( "HTMLEntityCodec" ); - list.add( "PercentCodec" ); - Encoder fileEncoder = new DefaultEncoder( list ); - fileValidator = new DefaultValidator( fileEncoder ); - } + /** Initialize file validator with an appropriate set of codecs */ + static { + List list = new ArrayList(); + list.add( "HTMLEntityCodec" ); + list.add( "PercentCodec" ); + Encoder fileEncoder = new DefaultEncoder( list ); + fileValidator = new DefaultValidator( fileEncoder ); + } + + + /** + * Default constructor uses the ESAPI standard encoder for canonicalization. + */ + public DefaultValidator() { + this.encoder = ESAPI.encoder(); + } + + /** + * Construct a new DefaultValidator that will use the specified + * Encoder for canonicalization. + * + * @param encoder + */ + public DefaultValidator( Encoder encoder ) { + this.encoder = encoder; + } + + + /** + * Add a validation rule to the registry using the "type name" of the rule as the key. + */ + public void addRule( ValidationRule rule ) { + rules.put( rule.getTypeName(), rule ); + } + + /** + * Get a validation rule from the registry with the "type name" of the rule as the key. + */ + public ValidationRule getRule( String name ) { + return rules.get( name ); + } + + + /** + * Returns true if data received from browser is valid. Double encoding is treated as an attack. The + * default encoder supports html encoding, URL encoding, and javascript escaping. Input is canonicalized + * by default before validation. + * + * @param context A descriptive name for the field to validate. This is used for error facing validation messages and element identification. + * @param input The actual user input data to validate. + * @param type The regular expression name while maps to the actual regular expression from "ESAPI.properties". + * @param maxLength The maximum post-canonicalized String length allowed. + * @param allowNull If allowNull is true then a input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. + * @return The canonicalized user input. + * @throws IntrusionException + */ + public boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull) throws IntrusionException { + return isValidInput(context, input, type, maxLength, allowNull, true); + } + + public boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + return isValidInput(context, input, type, maxLength, allowNull, true, errors); + } + + public boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize) throws IntrusionException { + try { + getValidInput( context, input, type, maxLength, allowNull, canonicalize); + return true; + } catch( Exception e ) { + return false; + } + } + + public boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize, ValidationErrorList errors) throws IntrusionException { + try { + getValidInput( context, input, type, maxLength, allowNull, canonicalize); + return true; + } catch( ValidationException e ) { + errors.addError( context, e ); + return false; + } + } + + /** + * Validates data received from the browser and returns a safe version. + * Double encoding is treated as an attack. The default encoder supports + * html encoding, URL encoding, and javascript escaping. Input is + * canonicalized by default before validation. + * + * @param context A descriptive name for the field to validate. This is used for error facing validation messages and element identification. + * @param input The actual user input data to validate. + * @param type The regular expression name which maps to the actual regular expression from "ESAPI.properties". + * @param maxLength The maximum post-canonicalized String length allowed. + * @param allowNull If allowNull is true then a input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. + * @return The canonicalized user input. + * @throws ValidationException + * @throws IntrusionException + */ + public String getValidInput(String context, String input, String type, int maxLength, boolean allowNull) throws ValidationException { + return getValidInput(context, input, type, maxLength, allowNull, true); + } + + /** + * Validates data received from the browser and returns a safe version. Only + * URL encoding is supported. Double encoding is treated as an attack. + * + * @param context A descriptive name for the field to validate. This is used for error facing validation messages and element identification. + * @param input The actual user input data to validate. + * @param type The regular expression name which maps to the actual regular expression in the ESAPI validation configuration file + * @param maxLength The maximum String length allowed. If input is canonicalized per the canonicalize argument, then maxLength must be verified after canonicalization + * @param allowNull If allowNull is true then a input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. + * @param canonicalize If canonicalize is true then input will be canonicalized before validation + * @return The user input, may be canonicalized if canonicalize argument is true + * @throws ValidationException + * @throws IntrusionException + */ + public String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize) throws ValidationException { + StringValidationRule rvr = new StringValidationRule( type, encoder ); + Pattern p = ESAPI.securityConfiguration().getValidationPattern( type ); + if ( p != null ) { + rvr.addWhitelistPattern( p ); + } else { + // Issue 232 - Specify requested type in exception message - CS + throw new IllegalArgumentException("The selected type [" + type + "] was not set via the ESAPI validation configuration"); + } + rvr.setMaximumLength(maxLength); + rvr.setAllowNull(allowNull); + rvr.setCanonicalize(canonicalize); + return rvr.getValid(context, input); + } + + /** + * Validates data received from the browser and returns a safe version. Only + * URL encoding is supported. Double encoding is treated as an attack. Input + * is canonicalized by default before validation. + * + * @param context A descriptive name for the field to validate. This is used for error facing validation messages and element identification. + * @param input The actual user input data to validate. + * @param type The regular expression name while maps to the actual regular expression from "ESAPI.properties". + * @param maxLength The maximum String length allowed. If input is canonicalized per the canonicalize argument, then maxLength must be verified after canonicalization + * @param allowNull If allowNull is true then a input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. + * @param errors If ValidationException is thrown, then add to error list instead of throwing out to caller + * @return The canonicalized user input. + * @throws IntrusionException + */ + public String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + return getValidInput(context, input, type, maxLength, allowNull, true, errors); + } + + /** + * Validates data received from the browser and returns a safe version. Only + * URL encoding is supported. Double encoding is treated as an attack. + * + * @param context A descriptive name for the field to validate. This is used for error facing validation messages and element identification. + * @param input The actual user input data to validate. + * @param type The regular expression name while maps to the actual regular expression from "ESAPI.properties". + * @param maxLength The maximum post-canonicalized String length allowed + * @param allowNull If allowNull is true then a input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. + * @param canonicalize If canonicalize is true then input will be canonicalized before validation + * @param errors If ValidationException is thrown, then add to error list instead of throwing out to caller + * @return The user input, may be canonicalized if canonicalize argument is true + * @throws IntrusionException + */ + public String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize, ValidationErrorList errors) throws IntrusionException { + try { + return getValidInput(context, input, type, maxLength, allowNull, canonicalize); + } catch (ValidationException e) { + errors.addError(context, e); + } + + return ""; + } + + /** + * {@inheritDoc} + */ + public boolean isValidDate(String context, String input, DateFormat format, boolean allowNull) throws IntrusionException { + try { + getValidDate( context, input, format, allowNull); + return true; + } catch( Exception e ) { + return false; + } + } + + /** + * {@inheritDoc} + */ + public boolean isValidDate(String context, String input, DateFormat format, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + getValidDate( context, input, format, allowNull, errors); + return errors.isEmpty(); + } + + /** + * {@inheritDoc} + */ + public Date getValidDate(String context, String input, DateFormat format, boolean allowNull) throws ValidationException, IntrusionException { + + ValidationErrorList vel = new ValidationErrorList(); + Date validDate = getValidDate(context, input, format, allowNull, vel); + + if (vel.isEmpty()) { + return validDate; + } + + throw vel.errors().get(0); + } + + /** + * {@inheritDoc} + */ + public Date getValidDate(String context, String input, DateFormat format, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + Date safeDate = null; + DateValidationRule dvr = new DateValidationRule( "SimpleDate", encoder, format); + dvr.setAllowNull(allowNull); + safeDate = dvr.sanitize(context, input, errors); + if (!errors.isEmpty()) { + safeDate = null; + } + // error has been added to list, so return null + return safeDate; + } + + /** + * {@inheritDoc} + */ + public boolean isValidSafeHTML(String context, String input, int maxLength, boolean allowNull) throws IntrusionException { + try { + getValidSafeHTML( context, input, maxLength, allowNull); + return true; + } catch( Exception e ) { + return false; + } + } + + /** + * {@inheritDoc} + */ + public boolean isValidSafeHTML(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + try { + getValidSafeHTML( context, input, maxLength, allowNull); + return true; + } catch( ValidationException e ) { + errors.addError(context, e); + return false; + } + } + + /** + * {@inheritDoc} + * + * This implementation relies on the OWASP AntiSamy project. + */ + public String getValidSafeHTML( String context, String input, int maxLength, boolean allowNull ) throws ValidationException, IntrusionException { + HTMLValidationRule hvr = new HTMLValidationRule( "safehtml", encoder ); + hvr.setMaximumLength(maxLength); + hvr.setAllowNull(allowNull); + return hvr.getValid(context, input); + } + + /** + * {@inheritDoc} + */ + public String getValidSafeHTML(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + try { + return getValidSafeHTML(context, input, maxLength, allowNull); + } catch (ValidationException e) { + errors.addError(context, e); + } + + return ""; + } + + /** + * {@inheritDoc} + */ + public boolean isValidCreditCard(String context, String input, boolean allowNull) throws IntrusionException { + try { + getValidCreditCard( context, input, allowNull); + return true; + } catch( Exception e ) { + return false; + } + } + + /** + * {@inheritDoc} + */ + public boolean isValidCreditCard(String context, String input, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + try { + getValidCreditCard( context, input, allowNull); + return true; + } catch( ValidationException e ) { + errors.addError(context, e); + return false; + } + } + /** + * {@inheritDoc} + */ + public String getValidCreditCard(String context, String input, boolean allowNull) throws ValidationException, IntrusionException { + CreditCardValidationRule ccvr = new CreditCardValidationRule( "creditcard", encoder ); + ccvr.setAllowNull(allowNull); + return ccvr.getValid(context, input); + } + + /** + * {@inheritDoc} + */ + public String getValidCreditCard(String context, String input, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + try { + return getValidCreditCard(context, input, allowNull); + } catch (ValidationException e) { + errors.addError(context, e); + } + + return ""; + } + + /** + * {@inheritDoc} + * + *

    Note: On platforms that support symlinks, this function will fail canonicalization if directorypath + * is a symlink. For example, on MacOS X, /etc is actually /private/etc. If you mean to use /etc, use its real + * path (/private/etc), not the symlink (/etc).

    + */ + public boolean isValidDirectoryPath(String context, String input, File parent, boolean allowNull) throws IntrusionException { + try { + getValidDirectoryPath( context, input, parent, allowNull); + return true; + } catch( Exception e ) { + return false; + } + } + /** + * {@inheritDoc} + * + *

    Note: On platforms that support symlinks, this function will fail canonicalization if directorypath + * is a symlink. For example, on MacOS X, /etc is actually /private/etc. If you mean to use /etc, use its real + * path (/private/etc), not the symlink (/etc).

    + */ + public boolean isValidDirectoryPath(String context, String input, File parent, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + try { + getValidDirectoryPath( context, input, parent, allowNull); + return true; + } catch( ValidationException e ) { + errors.addError(context, e); + return false; + } + } + /** + * {@inheritDoc} + */ + public String getValidDirectoryPath(String context, String input, File parent, boolean allowNull) throws ValidationException, IntrusionException { + try { + if (isEmpty(input)) { + if (allowNull) return null; + throw new ValidationException( context + ": Input directory path required", "Input directory path required: context=" + context + ", input=" + input, context ); + } + + File dir = new File( input ); + + // check dir exists and parent exists and dir is inside parent + if ( !dir.exists() ) { + throw new ValidationException( context + ": Invalid directory name", "Invalid directory, does not exist: context=" + context + ", input=" + input ); + } + if ( !dir.isDirectory() ) { + throw new ValidationException( context + ": Invalid directory name", "Invalid directory, not a directory: context=" + context + ", input=" + input ); + } + if ( !parent.exists() ) { + throw new ValidationException( context + ": Invalid directory name", "Invalid directory, specified parent does not exist: context=" + context + ", input=" + input + ", parent=" + parent ); + } + if ( !parent.isDirectory() ) { + throw new ValidationException( context + ": Invalid directory name", "Invalid directory, specified parent is not a directory: context=" + context + ", input=" + input + ", parent=" + parent ); + } + if ( !dir.getCanonicalFile().toPath().startsWith( parent.getCanonicalFile().toPath() ) ) { // Fixes GHSL-2022-008 + throw new ValidationException( context + ": Invalid directory name", "Invalid directory, not inside specified parent: context=" + context + ", input=" + input + ", parent=" + parent ); + } - /** - * Default constructor uses the ESAPI standard encoder for canonicalization. - */ - public DefaultValidator() { - this.encoder = ESAPI.encoder(); - } + // check canonical form matches input + String canonicalPath = dir.getCanonicalPath(); + String canonical = fileValidator.getValidInput( context, canonicalPath, "DirectoryName", 255, false); + if ( !canonical.equals( input ) ) { + throw new ValidationException( context + ": Invalid directory name", "Invalid directory name does not match the canonical path: context=" + context + ", input=" + input + ", canonical=" + canonical, context ); + } + return canonical; + } catch (Exception e) { + throw new ValidationException( context + ": Invalid directory name", "Failure to validate directory path: context=" + context + ", input=" + input, e, context ); + } + } + + /** + * {@inheritDoc} + */ + public String getValidDirectoryPath(String context, String input, File parent, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + + try { + return getValidDirectoryPath(context, input, parent, allowNull); + } catch (ValidationException e) { + errors.addError(context, e); + } + + return ""; + } + + + /** + * {@inheritDoc} + */ + public boolean isValidFileName(String context, String input, boolean allowNull) throws IntrusionException { + return isValidFileName( context, input, ESAPI.securityConfiguration().getAllowedFileExtensions(), allowNull ); + } + + /** + * {@inheritDoc} + */ + public boolean isValidFileName(String context, String input, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + return isValidFileName( context, input, ESAPI.securityConfiguration().getAllowedFileExtensions(), allowNull, errors ); + } + + /** + * {@inheritDoc} + */ + public boolean isValidFileName(String context, String input, List allowedExtensions, boolean allowNull) throws IntrusionException { + try { + getValidFileName( context, input, allowedExtensions, allowNull); + return true; + } catch( Exception e ) { + return false; + } + } + + /** + * {@inheritDoc} + */ + public boolean isValidFileName(String context, String input, List allowedExtensions, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + try { + getValidFileName( context, input, allowedExtensions, allowNull); + return true; + } catch( ValidationException e ) { + errors.addError(context, e); + return false; + } + } + /** + * {@inheritDoc} + */ + public String getValidFileName(String context, String input, List allowedExtensions, boolean allowNull) throws ValidationException, IntrusionException { + if ((allowedExtensions == null) || (allowedExtensions.isEmpty())) { + throw new ValidationException( "Internal Error", "getValidFileName called with an empty or null list of allowed Extensions, therefore no files can be uploaded" ); + } + + String canonical = ""; + // detect path manipulation + try { + if (isEmpty(input)) { + if (allowNull) return null; + throw new ValidationException( context + ": Input file name required", "Input required: context=" + context + ", input=" + input, context ); + } + + // do basic validation + canonical = new File(input).getCanonicalFile().getName(); + getValidInput( context, input, "FileName", 255, true ); + + File f = new File(canonical); + String c = f.getCanonicalPath(); + String cpath = c.substring(c.lastIndexOf(File.separator) + 1); + + + // the path is valid if the input matches the canonical path + if (!input.equals(cpath)) { + throw new ValidationException( context + ": Invalid file name", "Invalid directory name does not match the canonical path: context=" + context + ", input=" + input + ", canonical=" + canonical, context ); + } + + } catch (IOException e) { + throw new ValidationException( context + ": Invalid file name", "Invalid file name does not exist: context=" + context + ", canonical=" + canonical, e, context ); + } + + // verify extensions + Iterator i = allowedExtensions.iterator(); + while (i.hasNext()) { + String ext = i.next(); + if (input.toLowerCase().endsWith(ext.toLowerCase())) { + return canonical; + } + } + throw new ValidationException( context + ": Invalid file name does not have valid extension ( "+allowedExtensions+")", "Invalid file name does not have valid extension ( "+allowedExtensions+"): context=" + context+", input=" + input, context ); + } + + /** + * {@inheritDoc} + */ + public String getValidFileName(String context, String input, List allowedParameters, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + try { + return getValidFileName(context, input, allowedParameters, allowNull); + } catch (ValidationException e) { + errors.addError(context, e); + } + + return ""; + } + + /** + * {@inheritDoc} + */ + public boolean isValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull) throws IntrusionException { + try { + getValidNumber(context, input, minValue, maxValue, allowNull); + return true; + } catch( Exception e ) { + return false; + } + } + + /** + * {@inheritDoc} + */ + public boolean isValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + try { + getValidNumber(context, input, minValue, maxValue, allowNull); + return true; + } catch( ValidationException e ) { + errors.addError(context, e); + return false; + } + } + + /** + * {@inheritDoc} + */ + public Double getValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull) throws ValidationException, IntrusionException { + Double minDoubleValue = new Double(minValue); + Double maxDoubleValue = new Double(maxValue); + return getValidDouble(context, input, minDoubleValue.doubleValue(), maxDoubleValue.doubleValue(), allowNull); + } + + /** + * {@inheritDoc} + */ + public Double getValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + try { + return getValidNumber(context, input, minValue, maxValue, allowNull); + } catch (ValidationException e) { + errors.addError(context, e); + } + + return null; + } + + /** + * {@inheritDoc} + */ + public boolean isValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull) throws IntrusionException { + try { + getValidDouble( context, input, minValue, maxValue, allowNull ); + return true; + } catch( Exception e ) { + return false; + } + } + + /** + * {@inheritDoc} + */ + public boolean isValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + try { + getValidDouble( context, input, minValue, maxValue, allowNull ); + return true; + } catch( ValidationException e ) { + errors.addError(context, e); + return false; + } + } - /** - * Construct a new DefaultValidator that will use the specified - * Encoder for canonicalization. - * - * @param encoder + /** + * {@inheritDoc} */ - public DefaultValidator( Encoder encoder ) { - this.encoder = encoder; - } - - - /** - * Add a validation rule to the registry using the "type name" of the rule as the key. - */ - public void addRule( ValidationRule rule ) { - rules.put( rule.getTypeName(), rule ); - } - - /** - * Get a validation rule from the registry with the "type name" of the rule as the key. - */ - public ValidationRule getRule( String name ) { - return rules.get( name ); - } - - - /** - * Returns true if data received from browser is valid. Double encoding is treated as an attack. The - * default encoder supports html encoding, URL encoding, and javascript escaping. Input is canonicalized - * by default before validation. - * - * @param context A descriptive name for the field to validate. This is used for error facing validation messages and element identification. - * @param input The actual user input data to validate. - * @param type The regular expression name while maps to the actual regular expression from "ESAPI.properties". - * @param maxLength The maximum post-canonicalized String length allowed. - * @param allowNull If allowNull is true then a input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. - * @return The canonicalized user input. - * @throws IntrusionException - */ - public boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull) throws IntrusionException { - return isValidInput(context, input, type, maxLength, allowNull, true); - } + public Double getValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull) throws ValidationException, IntrusionException { + NumberValidationRule nvr = new NumberValidationRule( "number", encoder, minValue, maxValue ); + nvr.setAllowNull(allowNull); + return nvr.getValid(context, input); + } - public boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - return isValidInput(context, input, type, maxLength, allowNull, true, errors); - } - - public boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize) throws IntrusionException { - try { - getValidInput( context, input, type, maxLength, allowNull, canonicalize); - return true; - } catch( Exception e ) { - return false; - } - } + /** + * {@inheritDoc} + */ + public Double getValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + try { + return getValidDouble(context, input, minValue, maxValue, allowNull); + } catch (ValidationException e) { + errors.addError(context, e); + } - public boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize, ValidationErrorList errors) throws IntrusionException { - try { - getValidInput( context, input, type, maxLength, allowNull, canonicalize); - return true; - } catch( ValidationException e ) { - errors.addError( context, e ); - return false; - } - } - - /** - * Validates data received from the browser and returns a safe version. - * Double encoding is treated as an attack. The default encoder supports - * html encoding, URL encoding, and javascript escaping. Input is - * canonicalized by default before validation. - * - * @param context A descriptive name for the field to validate. This is used for error facing validation messages and element identification. - * @param input The actual user input data to validate. - * @param type The regular expression name which maps to the actual regular expression from "ESAPI.properties". - * @param maxLength The maximum post-canonicalized String length allowed. - * @param allowNull If allowNull is true then a input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. - * @return The canonicalized user input. - * @throws ValidationException - * @throws IntrusionException - */ - public String getValidInput(String context, String input, String type, int maxLength, boolean allowNull) throws ValidationException { - return getValidInput(context, input, type, maxLength, allowNull, true); - } - - /** - * Validates data received from the browser and returns a safe version. Only - * URL encoding is supported. Double encoding is treated as an attack. - * - * @param context A descriptive name for the field to validate. This is used for error facing validation messages and element identification. - * @param input The actual user input data to validate. - * @param type The regular expression name which maps to the actual regular expression in the ESAPI validation configuration file - * @param maxLength The maximum String length allowed. If input is canonicalized per the canonicalize argument, then maxLength must be verified after canonicalization - * @param allowNull If allowNull is true then a input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. - * @param canonicalize If canonicalize is true then input will be canonicalized before validation - * @return The user input, may be canonicalized if canonicalize argument is true - * @throws ValidationException - * @throws IntrusionException - */ - public String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize) throws ValidationException { - StringValidationRule rvr = new StringValidationRule( type, encoder ); - Pattern p = ESAPI.securityConfiguration().getValidationPattern( type ); - if ( p != null ) { - rvr.addWhitelistPattern( p ); - } else { - // Issue 232 - Specify requested type in exception message - CS - throw new IllegalArgumentException("The selected type [" + type + "] was not set via the ESAPI validation configuration"); - } - rvr.setMaximumLength(maxLength); - rvr.setAllowNull(allowNull); - rvr.setCanonicalize(canonicalize); - return rvr.getValid(context, input); - } - - /** - * Validates data received from the browser and returns a safe version. Only - * URL encoding is supported. Double encoding is treated as an attack. Input - * is canonicalized by default before validation. - * - * @param context A descriptive name for the field to validate. This is used for error facing validation messages and element identification. - * @param input The actual user input data to validate. - * @param type The regular expression name while maps to the actual regular expression from "ESAPI.properties". - * @param maxLength The maximum String length allowed. If input is canonicalized per the canonicalize argument, then maxLength must be verified after canonicalization - * @param allowNull If allowNull is true then a input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. - * @param errors If ValidationException is thrown, then add to error list instead of throwing out to caller - * @return The canonicalized user input. - * @throws IntrusionException - */ - public String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - return getValidInput(context, input, type, maxLength, allowNull, true, errors); - } - - /** - * Validates data received from the browser and returns a safe version. Only - * URL encoding is supported. Double encoding is treated as an attack. - * - * @param context A descriptive name for the field to validate. This is used for error facing validation messages and element identification. - * @param input The actual user input data to validate. - * @param type The regular expression name while maps to the actual regular expression from "ESAPI.properties". - * @param maxLength The maximum post-canonicalized String length allowed - * @param allowNull If allowNull is true then a input that is NULL or an empty string will be legal. If allowNull is false then NULL or an empty String will throw a ValidationException. - * @param canonicalize If canonicalize is true then input will be canonicalized before validation - * @param errors If ValidationException is thrown, then add to error list instead of throwing out to caller - * @return The user input, may be canonicalized if canonicalize argument is true - * @throws IntrusionException - */ - public String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, boolean canonicalize, ValidationErrorList errors) throws IntrusionException { - try { - return getValidInput(context, input, type, maxLength, allowNull, canonicalize); - } catch (ValidationException e) { - errors.addError(context, e); - } - - return ""; - } - - /** - * {@inheritDoc} - */ - public boolean isValidDate(String context, String input, DateFormat format, boolean allowNull) throws IntrusionException { - try { - getValidDate( context, input, format, allowNull); - return true; - } catch( Exception e ) { - return false; - } - } + return new Double(Double.NaN); + } - /** - * {@inheritDoc} - */ - public boolean isValidDate(String context, String input, DateFormat format, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - getValidDate( context, input, format, allowNull, errors); - return errors.isEmpty(); - } - - /** - * {@inheritDoc} - */ - public Date getValidDate(String context, String input, DateFormat format, boolean allowNull) throws ValidationException, IntrusionException { - - ValidationErrorList vel = new ValidationErrorList(); - Date validDate = getValidDate(context, input, format, allowNull, vel); - - if (vel.isEmpty()) { - return validDate; - } - - throw vel.errors().get(0); - } - - /** - * {@inheritDoc} - */ - public Date getValidDate(String context, String input, DateFormat format, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - Date safeDate = null; - DateValidationRule dvr = new DateValidationRule( "SimpleDate", encoder, format); - dvr.setAllowNull(allowNull); - safeDate = dvr.sanitize(context, input, errors); - if (!errors.isEmpty()) { - safeDate = null; - } - // error has been added to list, so return null - return safeDate; - } - - /** - * {@inheritDoc} - */ - public boolean isValidSafeHTML(String context, String input, int maxLength, boolean allowNull) throws IntrusionException { - try { - getValidSafeHTML( context, input, maxLength, allowNull); - return true; - } catch( Exception e ) { - return false; - } - } + /** + * {@inheritDoc} + */ + public boolean isValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull) throws IntrusionException { + try { + getValidInteger( context, input, minValue, maxValue, allowNull); + return true; + } catch( ValidationException e ) { + return false; + } + } /** - * {@inheritDoc} - */ - public boolean isValidSafeHTML(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - try { - getValidSafeHTML( context, input, maxLength, allowNull); - return true; - } catch( ValidationException e ) { + * {@inheritDoc} + */ + public boolean isValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + try { + getValidInteger( context, input, minValue, maxValue, allowNull); + return true; + } catch( ValidationException e ) { errors.addError(context, e); - return false; - } - } - - /** - * {@inheritDoc} - * - * This implementation relies on the OWASP AntiSamy project. - */ - public String getValidSafeHTML( String context, String input, int maxLength, boolean allowNull ) throws ValidationException, IntrusionException { - HTMLValidationRule hvr = new HTMLValidationRule( "safehtml", encoder ); - hvr.setMaximumLength(maxLength); - hvr.setAllowNull(allowNull); - return hvr.getValid(context, input); - } - - /** - * {@inheritDoc} - */ - public String getValidSafeHTML(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - try { - return getValidSafeHTML(context, input, maxLength, allowNull); - } catch (ValidationException e) { - errors.addError(context, e); - } - - return ""; - } - - /** - * {@inheritDoc} - */ - public boolean isValidCreditCard(String context, String input, boolean allowNull) throws IntrusionException { - try { - getValidCreditCard( context, input, allowNull); - return true; - } catch( Exception e ) { - return false; - } - } + return false; + } + } - /** - * {@inheritDoc} - */ - public boolean isValidCreditCard(String context, String input, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - try { - getValidCreditCard( context, input, allowNull); - return true; - } catch( ValidationException e ) { + /** + * {@inheritDoc} + */ + public Integer getValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull) throws ValidationException, IntrusionException { + IntegerValidationRule ivr = new IntegerValidationRule( "number", encoder, minValue, maxValue ); + ivr.setAllowNull(allowNull); + return ivr.getValid(context, input); + } + + /** + * {@inheritDoc} + */ + public Integer getValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + try { + return getValidInteger(context, input, minValue, maxValue, allowNull); + } catch (ValidationException e) { errors.addError(context, e); - return false; - } - } - /** - * {@inheritDoc} - */ - public String getValidCreditCard(String context, String input, boolean allowNull) throws ValidationException, IntrusionException { - CreditCardValidationRule ccvr = new CreditCardValidationRule( "creditcard", encoder ); - ccvr.setAllowNull(allowNull); - return ccvr.getValid(context, input); - } - - /** - * {@inheritDoc} - */ - public String getValidCreditCard(String context, String input, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - try { - return getValidCreditCard(context, input, allowNull); - } catch (ValidationException e) { - errors.addError(context, e); - } - - return ""; - } - - /** - * {@inheritDoc} - * - *

    Note: On platforms that support symlinks, this function will fail canonicalization if directorypath - * is a symlink. For example, on MacOS X, /etc is actually /private/etc. If you mean to use /etc, use its real - * path (/private/etc), not the symlink (/etc).

    - */ - public boolean isValidDirectoryPath(String context, String input, File parent, boolean allowNull) throws IntrusionException { - try { - getValidDirectoryPath( context, input, parent, allowNull); - return true; - } catch( Exception e ) { - return false; - } - } + } + // error has been added to list, so return original input + return null; + } + + /** + * {@inheritDoc} + */ + public boolean isValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull) throws IntrusionException { + try { + getValidFileContent( context, input, maxBytes, allowNull); + return true; + } catch( Exception e ) { + return false; + } + } /** - * {@inheritDoc} - * - *

    Note: On platforms that support symlinks, this function will fail canonicalization if directorypath - * is a symlink. For example, on MacOS X, /etc is actually /private/etc. If you mean to use /etc, use its real - * path (/private/etc), not the symlink (/etc).

    - */ - public boolean isValidDirectoryPath(String context, String input, File parent, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - try { - getValidDirectoryPath( context, input, parent, allowNull); - return true; - } catch( ValidationException e ) { + * {@inheritDoc} + */ + public boolean isValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + try { + getValidFileContent( context, input, maxBytes, allowNull); + return true; + } catch( ValidationException e ) { errors.addError(context, e); - return false; - } - } - /** - * {@inheritDoc} - */ - public String getValidDirectoryPath(String context, String input, File parent, boolean allowNull) throws ValidationException, IntrusionException { - try { - if (isEmpty(input)) { - if (allowNull) return null; - throw new ValidationException( context + ": Input directory path required", "Input directory path required: context=" + context + ", input=" + input, context ); - } - - File dir = new File( input ); - - // check dir exists and parent exists and dir is inside parent - if ( !dir.exists() ) { - throw new ValidationException( context + ": Invalid directory name", "Invalid directory, does not exist: context=" + context + ", input=" + input ); - } - if ( !dir.isDirectory() ) { - throw new ValidationException( context + ": Invalid directory name", "Invalid directory, not a directory: context=" + context + ", input=" + input ); - } - if ( !parent.exists() ) { - throw new ValidationException( context + ": Invalid directory name", "Invalid directory, specified parent does not exist: context=" + context + ", input=" + input + ", parent=" + parent ); - } - if ( !parent.isDirectory() ) { - throw new ValidationException( context + ": Invalid directory name", "Invalid directory, specified parent is not a directory: context=" + context + ", input=" + input + ", parent=" + parent ); - } - if ( !dir.getCanonicalFile().toPath().startsWith( parent.getCanonicalFile().toPath() ) ) { // Fixes GHSL-2022-008 - throw new ValidationException( context + ": Invalid directory name", "Invalid directory, not inside specified parent: context=" + context + ", input=" + input + ", parent=" + parent ); - } - - // check canonical form matches input - String canonicalPath = dir.getCanonicalPath(); - String canonical = fileValidator.getValidInput( context, canonicalPath, "DirectoryName", 255, false); - if ( !canonical.equals( input ) ) { - throw new ValidationException( context + ": Invalid directory name", "Invalid directory name does not match the canonical path: context=" + context + ", input=" + input + ", canonical=" + canonical, context ); - } - return canonical; - } catch (Exception e) { - throw new ValidationException( context + ": Invalid directory name", "Failure to validate directory path: context=" + context + ", input=" + input, e, context ); - } - } - - /** - * {@inheritDoc} - */ - public String getValidDirectoryPath(String context, String input, File parent, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - - try { - return getValidDirectoryPath(context, input, parent, allowNull); - } catch (ValidationException e) { - errors.addError(context, e); - } - - return ""; - } - - - /** - * {@inheritDoc} - */ - public boolean isValidFileName(String context, String input, boolean allowNull) throws IntrusionException { - return isValidFileName( context, input, ESAPI.securityConfiguration().getAllowedFileExtensions(), allowNull ); - } + return false; + } + } - /** - * {@inheritDoc} - */ - public boolean isValidFileName(String context, String input, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - return isValidFileName( context, input, ESAPI.securityConfiguration().getAllowedFileExtensions(), allowNull, errors ); - } - - /** - * {@inheritDoc} - */ - public boolean isValidFileName(String context, String input, List allowedExtensions, boolean allowNull) throws IntrusionException { - try { - getValidFileName( context, input, allowedExtensions, allowNull); - return true; - } catch( Exception e ) { - return false; - } - } + /** + * {@inheritDoc} + */ + public byte[] getValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull) throws ValidationException, IntrusionException { + if (isEmpty(input)) { + if (allowNull) return null; + throw new ValidationException( context + ": Input required", "Input required: context=" + context + ", input=" + Arrays.toString(input), context ); + } - /** - * {@inheritDoc} - */ - public boolean isValidFileName(String context, String input, List allowedExtensions, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - try { - getValidFileName( context, input, allowedExtensions, allowNull); - return true; - } catch( ValidationException e ) { + long esapiMaxBytes = ESAPI.securityConfiguration().getAllowedFileUploadSize(); + if (input.length > esapiMaxBytes ) throw new ValidationException( context + ": Invalid file content can not exceed " + esapiMaxBytes + " bytes", "Exceeded ESAPI max length", context ); + if (input.length > maxBytes ) throw new ValidationException( context + ": Invalid file content can not exceed " + maxBytes + " bytes", "Exceeded maxBytes ( " + input.length + ")", context ); + + return input; + } + + /** + * {@inheritDoc} + */ + public byte[] getValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + try { + return getValidFileContent(context, input, maxBytes, allowNull); + } catch (ValidationException e) { errors.addError(context, e); - return false; - } - } - /** - * {@inheritDoc} - */ - public String getValidFileName(String context, String input, List allowedExtensions, boolean allowNull) throws ValidationException, IntrusionException { - if ((allowedExtensions == null) || (allowedExtensions.isEmpty())) { - throw new ValidationException( "Internal Error", "getValidFileName called with an empty or null list of allowed Extensions, therefore no files can be uploaded" ); - } - - String canonical = ""; - // detect path manipulation - try { - if (isEmpty(input)) { - if (allowNull) return null; - throw new ValidationException( context + ": Input file name required", "Input required: context=" + context + ", input=" + input, context ); - } - - // do basic validation - canonical = new File(input).getCanonicalFile().getName(); - getValidInput( context, input, "FileName", 255, true ); - - File f = new File(canonical); - String c = f.getCanonicalPath(); - String cpath = c.substring(c.lastIndexOf(File.separator) + 1); - - - // the path is valid if the input matches the canonical path - if (!input.equals(cpath)) { - throw new ValidationException( context + ": Invalid file name", "Invalid directory name does not match the canonical path: context=" + context + ", input=" + input + ", canonical=" + canonical, context ); - } - - } catch (IOException e) { - throw new ValidationException( context + ": Invalid file name", "Invalid file name does not exist: context=" + context + ", canonical=" + canonical, e, context ); - } - - // verify extensions - Iterator i = allowedExtensions.iterator(); - while (i.hasNext()) { - String ext = i.next(); - if (input.toLowerCase().endsWith(ext.toLowerCase())) { - return canonical; - } - } - throw new ValidationException( context + ": Invalid file name does not have valid extension ( "+allowedExtensions+")", "Invalid file name does not have valid extension ( "+allowedExtensions+"): context=" + context+", input=" + input, context ); - } - - /** - * {@inheritDoc} - */ - public String getValidFileName(String context, String input, List allowedParameters, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - try { - return getValidFileName(context, input, allowedParameters, allowNull); - } catch (ValidationException e) { - errors.addError(context, e); - } - - return ""; - } - - /** - * {@inheritDoc} - */ - public boolean isValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull) throws IntrusionException { - try { - getValidNumber(context, input, minValue, maxValue, allowNull); - return true; - } catch( Exception e ) { - return false; - } - } + } + // return empty byte array on error + return new byte[0]; + } + + /** + * {@inheritDoc} + * + *

    Note: On platforms that support symlinks, this function will fail canonicalization if directorypath + * is a symlink. For example, on MacOS X, /etc is actually /private/etc. If you mean to use /etc, use its real + * path (/private/etc), not the symlink (/etc).

    + */ + public boolean isValidFileUpload(String context, String directorypath, String filename, File parent, byte[] content, int maxBytes, boolean allowNull) throws IntrusionException { + return( isValidFileName( context, filename, allowNull ) && + isValidDirectoryPath( context, directorypath, parent, allowNull ) && + isValidFileContent( context, content, maxBytes, allowNull ) ); + } /** - * {@inheritDoc} - */ - public boolean isValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - try { - getValidNumber(context, input, minValue, maxValue, allowNull); - return true; - } catch( ValidationException e ) { + * {@inheritDoc} + * + *

    Note: On platforms that support symlinks, this function will fail canonicalization if directorypath + * is a symlink. For example, on MacOS X, /etc is actually /private/etc. If you mean to use /etc, use its real + * path (/private/etc), not the symlink (/etc).

    + */ + public boolean isValidFileUpload(String context, String directorypath, String filename, File parent, byte[] content, int maxBytes, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + return( isValidFileName( context, filename, allowNull, errors ) && + isValidDirectoryPath( context, directorypath, parent, allowNull, errors ) && + isValidFileContent( context, content, maxBytes, allowNull, errors ) ); + } + + /** + * {@inheritDoc} + */ + public void assertValidFileUpload(String context, String directorypath, String filename, File parent, byte[] content, int maxBytes, List allowedExtensions, boolean allowNull) throws ValidationException, IntrusionException { + getValidFileName( context, filename, allowedExtensions, allowNull ); + getValidDirectoryPath( context, directorypath, parent, allowNull ); + getValidFileContent( context, content, maxBytes, allowNull ); + } + + /** + * {@inheritDoc} + */ + public void assertValidFileUpload(String context, String filepath, String filename, File parent, byte[] content, int maxBytes, List allowedExtensions, boolean allowNull, ValidationErrorList errors) + throws IntrusionException { + try { + assertValidFileUpload(context, filepath, filename, parent, content, maxBytes, allowedExtensions, allowNull); + } catch (ValidationException e) { errors.addError(context, e); - return false; - } - } - - /** - * {@inheritDoc} - */ - public Double getValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull) throws ValidationException, IntrusionException { - Double minDoubleValue = new Double(minValue); - Double maxDoubleValue = new Double(maxValue); - return getValidDouble(context, input, minDoubleValue.doubleValue(), maxDoubleValue.doubleValue(), allowNull); - } - - /** - * {@inheritDoc} - */ - public Double getValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - try { - return getValidNumber(context, input, minValue, maxValue, allowNull); - } catch (ValidationException e) { - errors.addError(context, e); - } - - return null; - } - - /** - * {@inheritDoc} - */ - public boolean isValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull) throws IntrusionException { + } + } + + /** + * {@inheritDoc} + * + * Returns true if input is a valid list item. + */ + public boolean isValidListItem(String context, String input, List list) { try { - getValidDouble( context, input, minValue, maxValue, allowNull ); + getValidListItem( context, input, list); return true; } catch( Exception e ) { return false; } - } + } /** - * {@inheritDoc} - */ - public boolean isValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + * {@inheritDoc} + * + * Returns true if input is a valid list item. + */ + public boolean isValidListItem(String context, String input, List list, ValidationErrorList errors) { try { - getValidDouble( context, input, minValue, maxValue, allowNull ); + getValidListItem( context, input, list); return true; } catch( ValidationException e ) { errors.addError(context, e); return false; } - } - - /** - * {@inheritDoc} - */ - public Double getValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull) throws ValidationException, IntrusionException { - NumberValidationRule nvr = new NumberValidationRule( "number", encoder, minValue, maxValue ); - nvr.setAllowNull(allowNull); - return nvr.getValid(context, input); - } - - /** - * {@inheritDoc} - */ - public Double getValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - try { - return getValidDouble(context, input, minValue, maxValue, allowNull); - } catch (ValidationException e) { - errors.addError(context, e); - } - - return new Double(Double.NaN); - } - - /** - * {@inheritDoc} - */ - public boolean isValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull) throws IntrusionException { - try { - getValidInteger( context, input, minValue, maxValue, allowNull); - return true; - } catch( ValidationException e ) { - return false; - } - } - - /** - * {@inheritDoc} - */ - public boolean isValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - try { - getValidInteger( context, input, minValue, maxValue, allowNull); - return true; - } catch( ValidationException e ) { - errors.addError(context, e); - return false; - } - } - - /** - * {@inheritDoc} - */ - public Integer getValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull) throws ValidationException, IntrusionException { - IntegerValidationRule ivr = new IntegerValidationRule( "number", encoder, minValue, maxValue ); - ivr.setAllowNull(allowNull); - return ivr.getValid(context, input); - } - - /** - * {@inheritDoc} - */ - public Integer getValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - try { - return getValidInteger(context, input, minValue, maxValue, allowNull); - } catch (ValidationException e) { - errors.addError(context, e); - } - // error has been added to list, so return original input - return null; - } - - /** - * {@inheritDoc} - */ - public boolean isValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull) throws IntrusionException { - try { - getValidFileContent( context, input, maxBytes, allowNull); - return true; - } catch( Exception e ) { - return false; - } - } + } - /** - * {@inheritDoc} - */ - public boolean isValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - try { - getValidFileContent( context, input, maxBytes, allowNull); - return true; - } catch( ValidationException e ) { - errors.addError(context, e); - return false; - } - } - - /** - * {@inheritDoc} - */ - public byte[] getValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull) throws ValidationException, IntrusionException { - if (isEmpty(input)) { - if (allowNull) return null; - throw new ValidationException( context + ": Input required", "Input required: context=" + context + ", input=" + Arrays.toString(input), context ); - } - - long esapiMaxBytes = ESAPI.securityConfiguration().getAllowedFileUploadSize(); - if (input.length > esapiMaxBytes ) throw new ValidationException( context + ": Invalid file content can not exceed " + esapiMaxBytes + " bytes", "Exceeded ESAPI max length", context ); - if (input.length > maxBytes ) throw new ValidationException( context + ": Invalid file content can not exceed " + maxBytes + " bytes", "Exceeded maxBytes ( " + input.length + ")", context ); - - return input; - } - - /** - * {@inheritDoc} - */ - public byte[] getValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - try { - return getValidFileContent(context, input, maxBytes, allowNull); - } catch (ValidationException e) { - errors.addError(context, e); - } - // return empty byte array on error - return new byte[0]; - } - - /** - * {@inheritDoc} - * - *

    Note: On platforms that support symlinks, this function will fail canonicalization if directorypath - * is a symlink. For example, on MacOS X, /etc is actually /private/etc. If you mean to use /etc, use its real - * path (/private/etc), not the symlink (/etc).

    - */ - public boolean isValidFileUpload(String context, String directorypath, String filename, File parent, byte[] content, int maxBytes, boolean allowNull) throws IntrusionException { - return( isValidFileName( context, filename, allowNull ) && - isValidDirectoryPath( context, directorypath, parent, allowNull ) && - isValidFileContent( context, content, maxBytes, allowNull ) ); - } + /** + * Returns the list item that exactly matches the canonicalized input. Invalid or non-matching input + * will generate a descriptive ValidationException, and input that is clearly an attack + * will generate a descriptive IntrusionException. + */ + public String getValidListItem(String context, String input, List list) throws ValidationException, IntrusionException { + if (list.contains(input)) return input; + throw new ValidationException( context + ": Invalid list item", "Invalid list item: context=" + context + ", input=" + input, context ); + } - /** - * {@inheritDoc} - * - *

    Note: On platforms that support symlinks, this function will fail canonicalization if directorypath - * is a symlink. For example, on MacOS X, /etc is actually /private/etc. If you mean to use /etc, use its real - * path (/private/etc), not the symlink (/etc).

    - */ - public boolean isValidFileUpload(String context, String directorypath, String filename, File parent, byte[] content, int maxBytes, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - return( isValidFileName( context, filename, allowNull, errors ) && - isValidDirectoryPath( context, directorypath, parent, allowNull, errors ) && - isValidFileContent( context, content, maxBytes, allowNull, errors ) ); - } - - /** - * {@inheritDoc} - */ - public void assertValidFileUpload(String context, String directorypath, String filename, File parent, byte[] content, int maxBytes, List allowedExtensions, boolean allowNull) throws ValidationException, IntrusionException { - getValidFileName( context, filename, allowedExtensions, allowNull ); - getValidDirectoryPath( context, directorypath, parent, allowNull ); - getValidFileContent( context, content, maxBytes, allowNull ); - } - - /** - * {@inheritDoc} - */ - public void assertValidFileUpload(String context, String filepath, String filename, File parent, byte[] content, int maxBytes, List allowedExtensions, boolean allowNull, ValidationErrorList errors) - throws IntrusionException { - try { - assertValidFileUpload(context, filepath, filename, parent, content, maxBytes, allowedExtensions, allowNull); - } catch (ValidationException e) { - errors.addError(context, e); - } - } - - /** - * {@inheritDoc} - * - * Returns true if input is a valid list item. - */ - public boolean isValidListItem(String context, String input, List list) { - try { - getValidListItem( context, input, list); - return true; - } catch( Exception e ) { - return false; - } - } - /** - * {@inheritDoc} - * - * Returns true if input is a valid list item. - */ - public boolean isValidListItem(String context, String input, List list, ValidationErrorList errors) { - try { - getValidListItem( context, input, list); - return true; - } catch( ValidationException e ) { - errors.addError(context, e); - return false; - } - } - - /** - * Returns the list item that exactly matches the canonicalized input. Invalid or non-matching input - * will generate a descriptive ValidationException, and input that is clearly an attack - * will generate a descriptive IntrusionException. - */ - public String getValidListItem(String context, String input, List list) throws ValidationException, IntrusionException { - if (list.contains(input)) return input; - throw new ValidationException( context + ": Invalid list item", "Invalid list item: context=" + context + ", input=" + input, context ); - } - - - /** - * ValidationErrorList variant of getValidListItem + /** + * ValidationErrorList variant of getValidListItem * * @param errors */ - public String getValidListItem(String context, String input, List list, ValidationErrorList errors) throws IntrusionException { - try { - return getValidListItem(context, input, list); - } catch (ValidationException e) { - errors.addError(context, e); - } - // error has been added to list, so return original input - return input; - } - - /** - * {@inheritDoc} - */ - public boolean isValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set requiredNames, Set optionalNames) { - try { - assertValidHTTPRequestParameterSet( context, request, requiredNames, optionalNames); - return true; - } catch( Exception e ) { - return false; - } - } + public String getValidListItem(String context, String input, List list, ValidationErrorList errors) throws IntrusionException { + try { + return getValidListItem(context, input, list); + } catch (ValidationException e) { + errors.addError(context, e); + } + // error has been added to list, so return original input + return input; + } + + /** + * {@inheritDoc} + */ + public boolean isValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set requiredNames, Set optionalNames) { + try { + assertValidHTTPRequestParameterSet( context, request, requiredNames, optionalNames); + return true; + } catch( Exception e ) { + return false; + } + } /** - * {@inheritDoc} + * {@inheritDoc} */ - public boolean isValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set requiredNames, Set optionalNames, ValidationErrorList errors) { - try { - assertValidHTTPRequestParameterSet( context, request, requiredNames, optionalNames); - return true; - } catch( ValidationException e ) { + public boolean isValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set requiredNames, Set optionalNames, ValidationErrorList errors) { + try { + assertValidHTTPRequestParameterSet( context, request, requiredNames, optionalNames); + return true; + } catch( ValidationException e ) { errors.addError(context, e); - return false; - } - } - - /** - * Validates that the parameters in the current request contain all required parameters and only optional ones in - * addition. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack - * will generate a descriptive IntrusionException. - * - * Uses current HTTPRequest - */ - public void assertValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set required, Set optional) throws ValidationException, IntrusionException { - Set actualNames = request.getParameterMap().keySet(); - - // verify ALL required parameters are present - Set missing = new HashSet(required); - missing.removeAll(actualNames); - if (missing.size() > 0) { - throw new ValidationException( context + ": Invalid HTTP request missing parameters", "Invalid HTTP request missing parameters " + missing + ": context=" + context, context ); - } - - // verify ONLY optional + required parameters are present - Set extra = new HashSet(actualNames); - extra.removeAll(required); - extra.removeAll(optional); - if (extra.size() > 0) { - throw new ValidationException( context + ": Invalid HTTP request extra parameters " + extra, "Invalid HTTP request extra parameters " + extra + ": context=" + context, context ); - } - } - - /** - * ValidationErrorList variant of assertIsValidHTTPRequestParameterSet + return false; + } + } + + /** + * Validates that the parameters in the current request contain all required parameters and only optional ones in + * addition. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack + * will generate a descriptive IntrusionException. + * + * Uses current HTTPRequest + */ + public void assertValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set required, Set optional) throws ValidationException, IntrusionException { + Set actualNames = request.getParameterMap().keySet(); + + // verify ALL required parameters are present + Set missing = new HashSet(required); + missing.removeAll(actualNames); + if (missing.size() > 0) { + throw new ValidationException( context + ": Invalid HTTP request missing parameters", "Invalid HTTP request missing parameters " + missing + ": context=" + context, context ); + } + + // verify ONLY optional + required parameters are present + Set extra = new HashSet(actualNames); + extra.removeAll(required); + extra.removeAll(optional); + if (extra.size() > 0) { + throw new ValidationException( context + ": Invalid HTTP request extra parameters " + extra, "Invalid HTTP request extra parameters " + extra + ": context=" + context, context ); + } + } + + /** + * ValidationErrorList variant of assertIsValidHTTPRequestParameterSet * - * Uses current HTTPRequest saved in ESAPI Authenticator + * Uses current HTTPRequest saved in ESAPI Authenticator * @param errors */ - public void assertValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set required, Set optional, ValidationErrorList errors) throws IntrusionException { - try { - assertValidHTTPRequestParameterSet(context, request, required, optional); - } catch (ValidationException e) { - errors.addError(context, e); - } - } + public void assertValidHTTPRequestParameterSet(String context, HttpServletRequest request, Set required, Set optional, ValidationErrorList errors) throws IntrusionException { + try { + assertValidHTTPRequestParameterSet(context, request, required, optional); + } catch (ValidationException e) { + errors.addError(context, e); + } + } - /** + /** * {@inheritDoc} * - * Checks that all bytes are valid ASCII characters (between 33 and 126 - * inclusive). This implementation does no decoding. http://en.wikipedia.org/wiki/ASCII. - */ - public boolean isValidPrintable(String context, char[] input, int maxLength, boolean allowNull) throws IntrusionException { - try { - getValidPrintable( context, input, maxLength, allowNull); - return true; - } catch( Exception e ) { - return false; - } - } + * Checks that all bytes are valid ASCII characters (between 33 and 126 + * inclusive). This implementation does no decoding. http://en.wikipedia.org/wiki/ASCII. + */ + public boolean isValidPrintable(String context, char[] input, int maxLength, boolean allowNull) throws IntrusionException { + try { + getValidPrintable( context, input, maxLength, allowNull); + return true; + } catch( Exception e ) { + return false; + } + } /** * {@inheritDoc} * - * Checks that all bytes are valid ASCII characters (between 33 and 126 - * inclusive). This implementation does no decoding. http://en.wikipedia.org/wiki/ASCII. - */ - public boolean isValidPrintable(String context, char[] input, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - try { - getValidPrintable( context, input, maxLength, allowNull); - return true; - } catch( ValidationException e ) { + * Checks that all bytes are valid ASCII characters (between 33 and 126 + * inclusive). This implementation does no decoding. http://en.wikipedia.org/wiki/ASCII. + */ + public boolean isValidPrintable(String context, char[] input, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + try { + getValidPrintable( context, input, maxLength, allowNull); + return true; + } catch( ValidationException e ) { errors.addError(context, e); - return false; - } - } + return false; + } + } - /** - * Returns canonicalized and validated printable characters as a byte array. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack - * will generate a descriptive IntrusionException. + /** + * Returns canonicalized and validated printable characters as a byte array. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack + * will generate a descriptive IntrusionException. * * @throws IntrusionException */ - public char[] getValidPrintable(String context, char[] input, int maxLength, boolean allowNull) throws ValidationException, IntrusionException { - if (isEmpty(input)) { - if (allowNull) return null; - throw new ValidationException(context + ": Input bytes required", "Input bytes required: HTTP request is null", context ); - } - - if (input.length > maxLength) { - throw new ValidationException(context + ": Input bytes can not exceed " + maxLength + " bytes", "Input exceeds maximum allowed length of " + maxLength + " by " + (input.length-maxLength) + " bytes: context=" + context + ", input=" + new String( input ), context); - } - - for (int i = 0; i < input.length; i++) { - if (input[i] <= 0x20 || input[i] >= 0x7E ) { - throw new ValidationException(context + ": Invalid input bytes: context=" + context, "Invalid non-ASCII input bytes, context=" + context + ", input=" + new String( input ), context); - } - } - return input; - } - - /** - * ValidationErrorList variant of getValidPrintable + public char[] getValidPrintable(String context, char[] input, int maxLength, boolean allowNull) throws ValidationException, IntrusionException { + if (isEmpty(input)) { + if (allowNull) return null; + throw new ValidationException(context + ": Input bytes required", "Input bytes required: HTTP request is null", context ); + } + + if (input.length > maxLength) { + throw new ValidationException(context + ": Input bytes can not exceed " + maxLength + " bytes", "Input exceeds maximum allowed length of " + maxLength + " by " + (input.length-maxLength) + " bytes: context=" + context + ", input=" + new String( input ), context); + } + + for (int i = 0; i < input.length; i++) { + if (input[i] <= 0x20 || input[i] >= 0x7E ) { + throw new ValidationException(context + ": Invalid input bytes: context=" + context, "Invalid non-ASCII input bytes, context=" + context + ", input=" + new String( input ), context); + } + } + return input; + } + + /** + * ValidationErrorList variant of getValidPrintable * * @param errors */ - public char[] getValidPrintable(String context, char[] input,int maxLength, boolean allowNull, ValidationErrorList errors) - throws IntrusionException { - - try { - return getValidPrintable(context, input, maxLength, allowNull); - } catch (ValidationException e) { - errors.addError(context, e); - } - // error has been added to list, so return original input - return input; - } - - - /** - * {@inheritDoc} - * - * Returns true if input is valid printable ASCII characters (32-126). - */ - public boolean isValidPrintable(String context, String input, int maxLength, boolean allowNull) throws IntrusionException { - try { - getValidPrintable( context, input, maxLength, allowNull); - return true; - } catch( Exception e ) { - return false; - } - } + public char[] getValidPrintable(String context, char[] input,int maxLength, boolean allowNull, ValidationErrorList errors) + throws IntrusionException { + + try { + return getValidPrintable(context, input, maxLength, allowNull); + } catch (ValidationException e) { + errors.addError(context, e); + } + // error has been added to list, so return original input + return input; + } + + + /** + * {@inheritDoc} + * + * Returns true if input is valid printable ASCII characters (32-126). + */ + public boolean isValidPrintable(String context, String input, int maxLength, boolean allowNull) throws IntrusionException { + try { + getValidPrintable( context, input, maxLength, allowNull); + return true; + } catch( Exception e ) { + return false; + } + } /** - * {@inheritDoc} - * - * Returns true if input is valid printable ASCII characters (32-126). - */ - public boolean isValidPrintable(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - try { - getValidPrintable( context, input, maxLength, allowNull); - return true; - } catch( ValidationException e ) { + * {@inheritDoc} + * + * Returns true if input is valid printable ASCII characters (32-126). + */ + public boolean isValidPrintable(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + try { + getValidPrintable( context, input, maxLength, allowNull); + return true; + } catch( ValidationException e ) { errors.addError(context, e); - return false; - } - } + return false; + } + } - /** - * Returns canonicalized and validated printable characters as a String. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack - * will generate a descriptive IntrusionException. + /** + * Returns canonicalized and validated printable characters as a String. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack + * will generate a descriptive IntrusionException. * * @throws IntrusionException */ - public String getValidPrintable(String context, String input, int maxLength, boolean allowNull) throws ValidationException, IntrusionException { - try { - String canonical = encoder.canonicalize(input); - return new String( getValidPrintable( context, canonical.toCharArray(), maxLength, allowNull) ); - //TODO - changed this to base Exception since we no longer need EncodingException - //TODO - this is a bit lame: we need to re-think this function. - } catch (Exception e) { - throw new ValidationException( context + ": Invalid printable input", "Invalid encoding of printable input, context=" + context + ", input=" + input, e, context); - } - } - - /** - * ValidationErrorList variant of getValidPrintable + public String getValidPrintable(String context, String input, int maxLength, boolean allowNull) throws ValidationException, IntrusionException { + try { + String canonical = encoder.canonicalize(input); + return new String( getValidPrintable( context, canonical.toCharArray(), maxLength, allowNull) ); + //TODO - changed this to base Exception since we no longer need EncodingException + //TODO - this is a bit lame: we need to re-think this function. + } catch (Exception e) { + throw new ValidationException( context + ": Invalid printable input", "Invalid encoding of printable input, context=" + context + ", input=" + input, e, context); + } + } + + /** + * ValidationErrorList variant of getValidPrintable * * @param errors */ - public String getValidPrintable(String context, String input,int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - try { - return getValidPrintable(context, input, maxLength, allowNull); - } catch (ValidationException e) { - errors.addError(context, e); - } - // error has been added to list, so return original input - return input; - } - - - /** - * Returns true if input is a valid redirect location. - */ - public boolean isValidRedirectLocation(String context, String input, boolean allowNull) throws IntrusionException { - SecurityConfiguration sc = ESAPI.securityConfiguration(); - return ESAPI.validator().isValidInput( context, input, "Redirect", sc.getIntProp("HttpUtilities.maxRedirectLength"), allowNull); - } + public String getValidPrintable(String context, String input,int maxLength, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + try { + return getValidPrintable(context, input, maxLength, allowNull); + } catch (ValidationException e) { + errors.addError(context, e); + } + // error has been added to list, so return original input + return input; + } + + + /** + * Returns true if input is a valid redirect location. + */ + public boolean isValidRedirectLocation(String context, String input, boolean allowNull) throws IntrusionException { + SecurityConfiguration sc = ESAPI.securityConfiguration(); + return ESAPI.validator().isValidInput( context, input, "Redirect", sc.getIntProp("HttpUtilities.maxRedirectLength"), allowNull); + } /** - * Returns true if input is a valid redirect location. - */ - public boolean isValidRedirectLocation(String context, String input, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - SecurityConfiguration sc = ESAPI.securityConfiguration(); - return ESAPI.validator().isValidInput( context, input, "Redirect", sc.getIntProp("HttpUtilities.maxRedirectLength"), allowNull, errors); - } - - - /** - * Returns a canonicalized and validated redirect location as a String. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack - * will generate a descriptive IntrusionException. - */ - public String getValidRedirectLocation(String context, String input, boolean allowNull) throws ValidationException, IntrusionException { - SecurityConfiguration sc = ESAPI.securityConfiguration(); - return ESAPI.validator().getValidInput( context, input, "Redirect", sc.getIntProp("HttpUtilities.maxRedirectLength"), allowNull); - } - - /** - * ValidationErrorList variant of getValidRedirectLocation + * Returns true if input is a valid redirect location. + */ + public boolean isValidRedirectLocation(String context, String input, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + SecurityConfiguration sc = ESAPI.securityConfiguration(); + return ESAPI.validator().isValidInput( context, input, "Redirect", sc.getIntProp("HttpUtilities.maxRedirectLength"), allowNull, errors); + } + + + /** + * Returns a canonicalized and validated redirect location as a String. Invalid input will generate a descriptive ValidationException, and input that is clearly an attack + * will generate a descriptive IntrusionException. + */ + public String getValidRedirectLocation(String context, String input, boolean allowNull) throws ValidationException, IntrusionException { + SecurityConfiguration sc = ESAPI.securityConfiguration(); + return ESAPI.validator().getValidInput( context, input, "Redirect", sc.getIntProp("HttpUtilities.maxRedirectLength"), allowNull); + } + + /** + * ValidationErrorList variant of getValidRedirectLocation * * @param errors */ - public String getValidRedirectLocation(String context, String input, boolean allowNull, ValidationErrorList errors) throws IntrusionException { - try { - return getValidRedirectLocation(context, input, allowNull); - } catch (ValidationException e) { - errors.addError(context, e); - } - // error has been added to list, so return original input - return input; - } - - /** + public String getValidRedirectLocation(String context, String input, boolean allowNull, ValidationErrorList errors) throws IntrusionException { + try { + return getValidRedirectLocation(context, input, allowNull); + } catch (ValidationException e) { + errors.addError(context, e); + } + // error has been added to list, so return original input + return input; + } + + /** * {@inheritDoc} * - * This implementation reads until a newline or the specified number of - * characters. + * This implementation reads until a newline or the specified number of + * characters. * * @param in * @param max */ - public String safeReadLine(InputStream in, int max) throws ValidationException { - if (max <= 0) { - throw new ValidationAvailabilityException( "Invalid input", "Invalid readline. Must read a positive number of bytes from the stream"); - } - - StringBuilder sb = new StringBuilder(); - int count = 0; - int c; - - try { - while (true) { - c = in.read(); - if ( c == -1 ) { - if (sb.length() == 0) { - return null; - } - break; - } - if (c == '\n' || c == '\r') { - break; - } - count++; - if (count > max) { - throw new ValidationAvailabilityException( "Invalid input", "Invalid readLine. Read more than maximum characters allowed (" + max + ")"); - } - sb.append((char) c); - } - return sb.toString(); - } catch (IOException e) { - throw new ValidationAvailabilityException( "Invalid input", "Invalid readLine. Problem reading from input stream", e); - } - } - - /** - * Helper function to check if a String is empty - * - * @param input string input value - * @return boolean response if input is empty or not - */ - private final boolean isEmpty(String input) { - return (input==null || input.trim().length() == 0); - } - - /** - * Helper function to check if a byte array is empty - * - * @param input string input value - * @return boolean response if input is empty or not - */ - private final boolean isEmpty(byte[] input) { - return (input==null || input.length == 0); - } - - - /** - * Helper function to check if a char array is empty - * - * @param input string input value - * @return boolean response if input is empty or not - */ - private final boolean isEmpty(char[] input) { - return (input==null || input.length == 0); - } - - /** - * {@inheritDoc} - */ - public boolean isValidURI(String context, String input, boolean allowNull) { - boolean isValid = false; - boolean inputIsNullOrEmpty = input == null || "".equals(input); - Encoder encoder = ESAPI.encoder(); - try{ - URI compliantURI = null == input ? new URI("") : this.getRfcCompliantURI(input); - if(null != compliantURI && input != null){ - String canonicalizedURI = encoder.getCanonicalizedURI(compliantURI); - //if getCanonicalizedURI doesn't throw an IntrusionException, then the URI contains no mixed or - //double-encoding attacks. - logger.debug(Logger.SECURITY_SUCCESS, "We did not detect any mixed or multiple encoding in the uri:[" + input + "]"); - Validator v = ESAPI.validator(); - //This part will use the regex from validation.properties. This regex should be super-simple, and - //used mainly to restrict certain parts of a URL. - Pattern p = ESAPI.securityConfiguration().getValidationPattern( "URL" ); - if(p != null){ - //We're doing this instead of using the normal validator API, because it will canonicalize the input again - //and if the URI has any queries that also happen to match HTML entities, like ¶ - //it will cease conforming to the regex we now specify for a URL. - isValid = p.matcher(canonicalizedURI).matches(); - }else{ - logger.error(Logger.EVENT_FAILURE, "Invalid regex pulled from configuration. Check the regex for URL and correct."); - } - }else{ - if(allowNull && inputIsNullOrEmpty ){ - isValid = true; - } - } - - }catch (IntrusionException e){ - logger.error(Logger.SECURITY_FAILURE, e.getMessage()); - isValid = false; - } catch (URISyntaxException e) { - logger.error(Logger.EVENT_FAILURE, e.getMessage()); - } - - - return isValid; - } - - /** - * {@inheritDoc} - */ - public URI getRfcCompliantURI(String input){ - URI rval = null; - try { - rval = new URI(input); - } catch (URISyntaxException e) { - logger.error(Logger.EVENT_FAILURE, e.getMessage()); - } - return rval; - } + public String safeReadLine(InputStream in, int max) throws ValidationException { + if (max <= 0) { + throw new ValidationAvailabilityException( "Invalid input", "Invalid readline. Must read a positive number of bytes from the stream"); + } + + StringBuilder sb = new StringBuilder(); + int count = 0; + int c; + + try { + while (true) { + c = in.read(); + if ( c == -1 ) { + if (sb.length() == 0) { + return null; + } + break; + } + if (c == '\n' || c == '\r') { + break; + } + count++; + if (count > max) { + throw new ValidationAvailabilityException( "Invalid input", "Invalid readLine. Read more than maximum characters allowed (" + max + ")"); + } + sb.append((char) c); + } + return sb.toString(); + } catch (IOException e) { + throw new ValidationAvailabilityException( "Invalid input", "Invalid readLine. Problem reading from input stream", e); + } + } + + /** + * Helper function to check if a String is empty + * + * @param input string input value + * @return boolean response if input is empty or not + */ + private final boolean isEmpty(String input) { + return (input==null || input.trim().length() == 0); + } + + /** + * Helper function to check if a byte array is empty + * + * @param input string input value + * @return boolean response if input is empty or not + */ + private final boolean isEmpty(byte[] input) { + return (input==null || input.length == 0); + } + + + /** + * Helper function to check if a char array is empty + * + * @param input string input value + * @return boolean response if input is empty or not + */ + private final boolean isEmpty(char[] input) { + return (input==null || input.length == 0); + } + + /** + * {@inheritDoc} + */ + public boolean isValidURI(String context, String input, boolean allowNull) { + boolean isValid = false; + boolean inputIsNullOrEmpty = input == null || "".equals(input); + Encoder encoder = ESAPI.encoder(); + try{ + URI compliantURI = null == input ? new URI("") : this.getRfcCompliantURI(input); + if(null != compliantURI && input != null){ + String canonicalizedURI = encoder.getCanonicalizedURI(compliantURI); + //if getCanonicalizedURI doesn't throw an IntrusionException, then the URI contains no mixed or + //double-encoding attacks. + logger.debug(Logger.SECURITY_SUCCESS, "We did not detect any mixed or multiple encoding in the uri:[" + input + "]"); + Validator v = ESAPI.validator(); + //This part will use the regex from validation.properties. This regex should be super-simple, and + //used mainly to restrict certain parts of a URL. + Pattern p = ESAPI.securityConfiguration().getValidationPattern( "URL" ); + if(p != null){ + //We're doing this instead of using the normal validator API, because it will canonicalize the input again + //and if the URI has any queries that also happen to match HTML entities, like ¶ + //it will cease conforming to the regex we now specify for a URL. + isValid = p.matcher(canonicalizedURI).matches(); + }else{ + logger.error(Logger.EVENT_FAILURE, "Invalid regex pulled from configuration. Check the regex for URL and correct."); + } + }else{ + if(allowNull && inputIsNullOrEmpty ){ + isValid = true; + } + } + + }catch (IntrusionException e){ + logger.error(Logger.SECURITY_FAILURE, e.getMessage()); + isValid = false; + } catch (URISyntaxException e) { + logger.error(Logger.EVENT_FAILURE, e.getMessage()); + } + + + return isValid; + } + + /** + * {@inheritDoc} + */ + public URI getRfcCompliantURI(String input){ + URI rval = null; + try { + rval = new URI(input); + } catch (URISyntaxException e) { + logger.error(Logger.EVENT_FAILURE, e.getMessage()); + } + return rval; + } } diff --git a/src/main/java/org/owasp/esapi/reference/FileBasedAuthenticator.java b/src/main/java/org/owasp/esapi/reference/FileBasedAuthenticator.java index 77d2a88c1..ed0b16b17 100644 --- a/src/main/java/org/owasp/esapi/reference/FileBasedAuthenticator.java +++ b/src/main/java/org/owasp/esapi/reference/FileBasedAuthenticator.java @@ -231,7 +231,7 @@ List getOldPasswordHashes(User user) { * */ private FileBasedAuthenticator() { - super(); + super(); } @@ -663,7 +663,7 @@ private String dump(Collection c) { sb.append(s).append(","); } if ( c.size() > 0) { - return sb.toString().substring(0, sb.length() - 1); + return sb.toString().substring(0, sb.length() - 1); } return ""; @@ -746,8 +746,8 @@ public void verifyPasswordStrength(String oldPassword, String newPassword, User //jtm - 11/3/2010 - fix for bug http://code.google.com/p/owasp-esapi-java/issues/detail?id=108 if (accountName.equalsIgnoreCase(newPassword)) { - //password can't be account name - throw new AuthenticationCredentialsException("Invalid password", "Password matches account name, irrespective of case"); + //password can't be account name + throw new AuthenticationCredentialsException("Invalid password", "Password matches account name, irrespective of case"); } } diff --git a/src/main/java/org/owasp/esapi/reference/IntegerAccessReferenceMap.java b/src/main/java/org/owasp/esapi/reference/IntegerAccessReferenceMap.java index 6f01e1fc1..32dab104a 100644 --- a/src/main/java/org/owasp/esapi/reference/IntegerAccessReferenceMap.java +++ b/src/main/java/org/owasp/esapi/reference/IntegerAccessReferenceMap.java @@ -28,53 +28,53 @@ */ public class IntegerAccessReferenceMap extends AbstractAccessReferenceMap { - private static final long serialVersionUID = 5311769278372489771L; + private static final long serialVersionUID = 5311769278372489771L; - int count = 1; + int count = 1; - /** - * TODO Javadoc - */ - public IntegerAccessReferenceMap() - { - } + /** + * TODO Javadoc + */ + public IntegerAccessReferenceMap() + { + } - /** - * TODO Javadoc - */ - public IntegerAccessReferenceMap(int initialSize) - { - super(initialSize); - } + /** + * TODO Javadoc + */ + public IntegerAccessReferenceMap(int initialSize) + { + super(initialSize); + } - /** - * TODO Javadoc - */ - public IntegerAccessReferenceMap(Set directReferences) - { - super(directReferences.size()); - update(directReferences); - } + /** + * TODO Javadoc + */ + public IntegerAccessReferenceMap(Set directReferences) + { + super(directReferences.size()); + update(directReferences); + } - /** - * TODO Javadoc - */ - public IntegerAccessReferenceMap(Set directReferences, int initialSize) - { - super(initialSize); - update(directReferences); - } + /** + * TODO Javadoc + */ + public IntegerAccessReferenceMap(Set directReferences, int initialSize) + { + super(initialSize); + update(directReferences); + } - /** + /** * {@inheritDoc} - * Note: this is final as redefinition by subclasses - * can lead to use before initialization issues as - * {@link #IntegerAccessReferenceMap(Set)} and - * {@link #IntegerAccessReferenceMap(Set,int)} both call it - * internally. - */ - protected final synchronized String getUniqueReference() { - return "" + count++; // returns a string version of the counter - } + * Note: this is final as redefinition by subclasses + * can lead to use before initialization issues as + * {@link #IntegerAccessReferenceMap(Set)} and + * {@link #IntegerAccessReferenceMap(Set,int)} both call it + * internally. + */ + protected final synchronized String getUniqueReference() { + return "" + count++; // returns a string version of the counter + } } diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/AlwaysFalseACR.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/AlwaysFalseACR.java index af22587e4..bd25ab86f 100644 --- a/src/main/java/org/owasp/esapi/reference/accesscontrol/AlwaysFalseACR.java +++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/AlwaysFalseACR.java @@ -2,8 +2,8 @@ public class AlwaysFalseACR extends BaseACR { -// @Override - public boolean isAuthorized(Object runtimeParameter) { - return false; - } +// @Override + public boolean isAuthorized(Object runtimeParameter) { + return false; + } } diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/AlwaysTrueACR.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/AlwaysTrueACR.java index 0c0c9de18..f58e4e783 100644 --- a/src/main/java/org/owasp/esapi/reference/accesscontrol/AlwaysTrueACR.java +++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/AlwaysTrueACR.java @@ -1,9 +1,9 @@ package org.owasp.esapi.reference.accesscontrol; public class AlwaysTrueACR extends BaseACR { - -// @Override - public boolean isAuthorized(Object runtimeParameter) { - return true; - } + +// @Override + public boolean isAuthorized(Object runtimeParameter) { + return true; + } } diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/BaseACR.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/BaseACR.java index f1699020c..8814b954f 100644 --- a/src/main/java/org/owasp/esapi/reference/accesscontrol/BaseACR.java +++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/BaseACR.java @@ -4,15 +4,15 @@ abstract public class BaseACR implements AccessControlRule { - protected P policyParameters; - -// @Override - public void setPolicyParameters(P policyParameter) { - this.policyParameters = policyParameter; - } - -// @Override - public P getPolicyParameters() { - return policyParameters; - } + protected P policyParameters; + +// @Override + public void setPolicyParameters(P policyParameter) { + this.policyParameters = policyParameter; + } + +// @Override + public P getPolicyParameters() { + return policyParameters; + } } diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/DelegatingACR.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/DelegatingACR.java index 65cb0ebb9..91a86d74b 100644 --- a/src/main/java/org/owasp/esapi/reference/accesscontrol/DelegatingACR.java +++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/DelegatingACR.java @@ -9,92 +9,92 @@ import org.apache.commons.collections4.iterators.ArrayListIterator; public class DelegatingACR extends BaseACR { - protected Method delegateMethod; - protected Object delegateInstance; - - @Override - public void setPolicyParameters(DynaBeanACRParameter policyParameter) { - String delegateClassName = policyParameter.getString("delegateClass", "").trim(); - String methodName = policyParameter.getString("delegateMethod", "").trim(); - String[] parameterClassNames = policyParameter.getStringArray("parameterClasses"); + protected Method delegateMethod; + protected Object delegateInstance; + + @Override + public void setPolicyParameters(DynaBeanACRParameter policyParameter) { + String delegateClassName = policyParameter.getString("delegateClass", "").trim(); + String methodName = policyParameter.getString("delegateMethod", "").trim(); + String[] parameterClassNames = policyParameter.getStringArray("parameterClasses"); - //Convert the classNames into Classes and get the delegate method. - Class delegateClass = getClass(delegateClassName, "delegate"); - Class parameterClasses[] = getParameters(parameterClassNames); - try { - this.delegateMethod = delegateClass.getMethod(methodName, parameterClasses); - } catch (SecurityException e) { - throw new IllegalArgumentException(e.getMessage() + - " delegateClass.delegateMethod(parameterClasses): \"" + - delegateClassName + "." + methodName + "(" + Arrays.toString(parameterClassNames) + - ")\" must be public.", e); - } catch (NoSuchMethodException e) { - throw new IllegalArgumentException(e.getMessage() + - " delegateClass.delegateMethod(parameterClasses): \"" + - delegateClassName + "." + methodName + "(" + Arrays.toString(parameterClassNames) + - ")\" does not exist.", e); - } - - //static methods do not need a delegateInstance. Non-static methods do. - if(!Modifier.isStatic(this.delegateMethod.getModifiers())) { - try { - this.delegateInstance = delegateClass.newInstance(); - } catch (InstantiationException ex) { - throw new IllegalArgumentException( - " Delegate class \"" + delegateClassName + - "\" must be concrete, because method " + - delegateClassName + "." + methodName + "(" + Arrays.toString(parameterClassNames) + - ") is not static.", ex); - } catch (IllegalAccessException ex) { - new IllegalArgumentException( - " Delegate class \"" + delegateClassName + - "\" must must have a zero-argument constructor, because " + - "method delegateClass.delegateMethod(parameterClasses): \"" + - delegateClassName + "." + methodName + "(" + Arrays.toString(parameterClassNames) + - ")\" is not static.", ex); - } - } else { - this.delegateInstance = null; - } - } - /** - * Convert an array of fully qualified class names into an array of Class objects - * @param parameterClassNames - * @return The Class objects found that match the specified class names provided. - */ - protected final Class[] getParameters(String[] parameterClassNames) { - if (parameterClassNames == null) { - return new Class[0]; - } - Vector classes = new Vector(); - Iterator classNames = new ArrayListIterator(parameterClassNames); - while(classNames.hasNext()) { - classes.add(getClass(classNames.next(), "parameter")); - } - return classes.toArray(new Class[classes.size()]); - } - /** - * Convert a single fully qualified class name into a Class object - * @param className - * @param purpose - * @return The Class matching the specified name, if it exists. - */ - protected final Class getClass(String className, String purpose) { - try { - Class theClass = Class.forName(className); - return theClass; - } catch ( ClassNotFoundException ex ) { - throw new IllegalArgumentException(ex.getMessage() + - " " + purpose + " Class " + className + - " must be in the classpath", ex); - } - } - /** - * Delegates to the method specified in setPolicyParameters - */ - public boolean isAuthorized(Object[] runtimeParameters) throws Exception { - return ((Boolean)delegateMethod.invoke(delegateInstance, runtimeParameters)).booleanValue(); - } + //Convert the classNames into Classes and get the delegate method. + Class delegateClass = getClass(delegateClassName, "delegate"); + Class parameterClasses[] = getParameters(parameterClassNames); + try { + this.delegateMethod = delegateClass.getMethod(methodName, parameterClasses); + } catch (SecurityException e) { + throw new IllegalArgumentException(e.getMessage() + + " delegateClass.delegateMethod(parameterClasses): \"" + + delegateClassName + "." + methodName + "(" + Arrays.toString(parameterClassNames) + + ")\" must be public.", e); + } catch (NoSuchMethodException e) { + throw new IllegalArgumentException(e.getMessage() + + " delegateClass.delegateMethod(parameterClasses): \"" + + delegateClassName + "." + methodName + "(" + Arrays.toString(parameterClassNames) + + ")\" does not exist.", e); + } + + //static methods do not need a delegateInstance. Non-static methods do. + if(!Modifier.isStatic(this.delegateMethod.getModifiers())) { + try { + this.delegateInstance = delegateClass.newInstance(); + } catch (InstantiationException ex) { + throw new IllegalArgumentException( + " Delegate class \"" + delegateClassName + + "\" must be concrete, because method " + + delegateClassName + "." + methodName + "(" + Arrays.toString(parameterClassNames) + + ") is not static.", ex); + } catch (IllegalAccessException ex) { + new IllegalArgumentException( + " Delegate class \"" + delegateClassName + + "\" must must have a zero-argument constructor, because " + + "method delegateClass.delegateMethod(parameterClasses): \"" + + delegateClassName + "." + methodName + "(" + Arrays.toString(parameterClassNames) + + ")\" is not static.", ex); + } + } else { + this.delegateInstance = null; + } + } + /** + * Convert an array of fully qualified class names into an array of Class objects + * @param parameterClassNames + * @return The Class objects found that match the specified class names provided. + */ + protected final Class[] getParameters(String[] parameterClassNames) { + if (parameterClassNames == null) { + return new Class[0]; + } + Vector classes = new Vector(); + Iterator classNames = new ArrayListIterator(parameterClassNames); + while(classNames.hasNext()) { + classes.add(getClass(classNames.next(), "parameter")); + } + return classes.toArray(new Class[classes.size()]); + } + /** + * Convert a single fully qualified class name into a Class object + * @param className + * @param purpose + * @return The Class matching the specified name, if it exists. + */ + protected final Class getClass(String className, String purpose) { + try { + Class theClass = Class.forName(className); + return theClass; + } catch ( ClassNotFoundException ex ) { + throw new IllegalArgumentException(ex.getMessage() + + " " + purpose + " Class " + className + + " must be in the classpath", ex); + } + } + /** + * Delegates to the method specified in setPolicyParameters + */ + public boolean isAuthorized(Object[] runtimeParameters) throws Exception { + return ((Boolean)delegateMethod.invoke(delegateInstance, runtimeParameters)).booleanValue(); + } } diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/DynaBeanACRParameter.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/DynaBeanACRParameter.java index 9f124172a..5eea24a91 100644 --- a/src/main/java/org/owasp/esapi/reference/accesscontrol/DynaBeanACRParameter.java +++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/DynaBeanACRParameter.java @@ -15,182 +15,182 @@ * @author Mike H. Fauzy */ public class DynaBeanACRParameter implements PolicyParameters { - protected LazyDynaMap policyProperties; - - public DynaBeanACRParameter() { - policyProperties = new LazyDynaMap(); - } - - /* (non-Javadoc) - * @see org.owasp.esapi.reference.accesscontrol.policyloader.PolicyParameters#get(java.lang.String) - */ - public Object get(String key) { - return policyProperties.get(key); - } - /** - * Convenience method to avoid common casts. - * @param key - * @return The true/false value of the specified key. False if not found. - */ - public boolean getBoolean(String key) { - return ((Boolean)get(key)).booleanValue(); - } - /** - * Convenience method to avoid common casts. - * @param key - * @return The byte value of the specified key. - */ - public byte getByte(String key) { - return ((Byte)get(key)).byteValue(); - } - /** - * Convenience method to avoid common casts. - * @param key - * @return The char value of the specified key. - */ - public char getChar(String key) { - return ((Character)get(key)).charValue(); - } - /** - * Convenience method to avoid common casts. - * @param key - * @return The int value of the specified key. - */ - public int getInt(String key) { - return ((Integer)get(key)).intValue(); - } - /** - * Convenience method to avoid common casts. - * @param key - * @return The long value of the specified key. - */ - public long getLong(String key) { - return ((Long)get(key)).longValue(); - } - /** - * Convenience method to avoid common casts. - * @param key - * @return The float value of the specified key. - */ - public float getFloat(String key) { - return ((Float)get(key)).floatValue(); - } - /** - * Convenience method to avoid common casts. - * @param key - * @return The double value of the specified key. - */ - public double getDouble(String key) { - return ((Double)get(key)).doubleValue(); - } - /** - * Convenience method to avoid common casts. - * @param key - * @return The BigDecimal value of the specified key. - */ - public BigDecimal getBigDecimal(String key) { - return (BigDecimal)get(key); - } - /** - * Convenience method to avoid common casts. - * @param key - * @return The BigInteger value of the specified key. - */ - public BigInteger getBigInteger(String key) { - return (BigInteger)get(key); - } - /** - * Convenience method to avoid common casts. - * @param key - * @return The Date value of the specified key. - */ - public Date getDate(String key) { - return (Date)get(key); - } - - /** - * Convenience method to avoid common casts. Note that the time object - * is the same as a date object - * @param key - * @return The Date value of the specified key. - */ - public Date getTime(String key) { - return (Date)get(key); - } - - /** - * Convenience method to avoid common casts. - * @param key - * @return The String value of the specified key. null if the key is not defined. - */ - public String getString(String key) { - return (String)get(key); - } - - /** - * Convenience method to avoid common casts. - * @param key - * @return The String value of the specified key. If the key is not defined, the default value is returned instead. - */ - public String getString(String key, String defaultValue) { - return (String)get(key) == null ? defaultValue : (String)get(key); - } - - /** - * Convenience method to avoid common casts. - * @param key - * @return The String[] value of the specified key. - */ - public String[] getStringArray(String key) { - return (String[])get(key); - } - - /** - * Convenience method to avoid common casts. - * @param key - * @return The value of the specified key, returned generically as an Object. - */ - public Object getObject(String key) { - return get(key); - } + protected LazyDynaMap policyProperties; + + public DynaBeanACRParameter() { + policyProperties = new LazyDynaMap(); + } + + /* (non-Javadoc) + * @see org.owasp.esapi.reference.accesscontrol.policyloader.PolicyParameters#get(java.lang.String) + */ + public Object get(String key) { + return policyProperties.get(key); + } + /** + * Convenience method to avoid common casts. + * @param key + * @return The true/false value of the specified key. False if not found. + */ + public boolean getBoolean(String key) { + return ((Boolean)get(key)).booleanValue(); + } + /** + * Convenience method to avoid common casts. + * @param key + * @return The byte value of the specified key. + */ + public byte getByte(String key) { + return ((Byte)get(key)).byteValue(); + } + /** + * Convenience method to avoid common casts. + * @param key + * @return The char value of the specified key. + */ + public char getChar(String key) { + return ((Character)get(key)).charValue(); + } + /** + * Convenience method to avoid common casts. + * @param key + * @return The int value of the specified key. + */ + public int getInt(String key) { + return ((Integer)get(key)).intValue(); + } + /** + * Convenience method to avoid common casts. + * @param key + * @return The long value of the specified key. + */ + public long getLong(String key) { + return ((Long)get(key)).longValue(); + } + /** + * Convenience method to avoid common casts. + * @param key + * @return The float value of the specified key. + */ + public float getFloat(String key) { + return ((Float)get(key)).floatValue(); + } + /** + * Convenience method to avoid common casts. + * @param key + * @return The double value of the specified key. + */ + public double getDouble(String key) { + return ((Double)get(key)).doubleValue(); + } + /** + * Convenience method to avoid common casts. + * @param key + * @return The BigDecimal value of the specified key. + */ + public BigDecimal getBigDecimal(String key) { + return (BigDecimal)get(key); + } + /** + * Convenience method to avoid common casts. + * @param key + * @return The BigInteger value of the specified key. + */ + public BigInteger getBigInteger(String key) { + return (BigInteger)get(key); + } + /** + * Convenience method to avoid common casts. + * @param key + * @return The Date value of the specified key. + */ + public Date getDate(String key) { + return (Date)get(key); + } + + /** + * Convenience method to avoid common casts. Note that the time object + * is the same as a date object + * @param key + * @return The Date value of the specified key. + */ + public Date getTime(String key) { + return (Date)get(key); + } + + /** + * Convenience method to avoid common casts. + * @param key + * @return The String value of the specified key. null if the key is not defined. + */ + public String getString(String key) { + return (String)get(key); + } + + /** + * Convenience method to avoid common casts. + * @param key + * @return The String value of the specified key. If the key is not defined, the default value is returned instead. + */ + public String getString(String key, String defaultValue) { + return (String)get(key) == null ? defaultValue : (String)get(key); + } + + /** + * Convenience method to avoid common casts. + * @param key + * @return The String[] value of the specified key. + */ + public String[] getStringArray(String key) { + return (String[])get(key); + } + + /** + * Convenience method to avoid common casts. + * @param key + * @return The value of the specified key, returned generically as an Object. + */ + public Object getObject(String key) { + return get(key); + } - /* (non-Javadoc) - * @see org.owasp.esapi.reference.accesscontrol.policyloader.PolicyParameters#set(java.lang.String, java.lang.Object) - */ - public void set(String key, Object value) throws IllegalArgumentException { - policyProperties.set(key, value); - } - /* (non-Javadoc) - * @see org.owasp.esapi.reference.accesscontrol.policyloader.PolicyParameters#put(java.lang.String, java.lang.Object) - */ - public void put(String key, Object value) throws IllegalArgumentException { - set(key, value); - } - - /** - * This makes the map itself read only, but the mutability of objects - * that this map contains is not affected. Specifically, properties - * cannot be added or removed and the reference cannot be changed to - * a different object, but this does not change whether the values that the - * object contains can be changed. - */ - public void lock() { - policyProperties.setRestricted(true); - } - - public String toString() { - StringBuilder sb = new StringBuilder(); - Iterator keys = policyProperties.getMap().keySet().iterator(); - String currentKey; - while(keys.hasNext()) { - currentKey = (String)keys.next(); - sb.append(currentKey); - sb.append("="); - sb.append(policyProperties.get(currentKey)); - if(keys.hasNext()) { - sb.append(","); - } - } - return sb.toString(); - } + /* (non-Javadoc) + * @see org.owasp.esapi.reference.accesscontrol.policyloader.PolicyParameters#set(java.lang.String, java.lang.Object) + */ + public void set(String key, Object value) throws IllegalArgumentException { + policyProperties.set(key, value); + } + /* (non-Javadoc) + * @see org.owasp.esapi.reference.accesscontrol.policyloader.PolicyParameters#put(java.lang.String, java.lang.Object) + */ + public void put(String key, Object value) throws IllegalArgumentException { + set(key, value); + } + + /** + * This makes the map itself read only, but the mutability of objects + * that this map contains is not affected. Specifically, properties + * cannot be added or removed and the reference cannot be changed to + * a different object, but this does not change whether the values that the + * object contains can be changed. + */ + public void lock() { + policyProperties.setRestricted(true); + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + Iterator keys = policyProperties.getMap().keySet().iterator(); + String currentKey; + while(keys.hasNext()) { + currentKey = (String)keys.next(); + sb.append(currentKey); + sb.append("="); + sb.append(policyProperties.get(currentKey)); + if(keys.hasNext()) { + sb.append(","); + } + } + return sb.toString(); + } } diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/EchoRuntimeParameterACR.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/EchoRuntimeParameterACR.java index b33007707..2bafc3864 100644 --- a/src/main/java/org/owasp/esapi/reference/accesscontrol/EchoRuntimeParameterACR.java +++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/EchoRuntimeParameterACR.java @@ -2,12 +2,12 @@ public class EchoRuntimeParameterACR extends BaseACR{ - /** - * Returns true iff runtimeParameter is a Boolean true. - * throws ClassCastException if runtimeParameter is not a Boolean. - */ - public boolean isAuthorized(Boolean runtimeParameter) throws ClassCastException{ - return runtimeParameter.booleanValue(); - } + /** + * Returns true iff runtimeParameter is a Boolean true. + * throws ClassCastException if runtimeParameter is not a Boolean. + */ + public boolean isAuthorized(Boolean runtimeParameter) throws ClassCastException{ + return runtimeParameter.booleanValue(); + } } \ No newline at end of file diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/ExperimentalAccessController.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/ExperimentalAccessController.java index 34936c72c..1d1d6d3a2 100644 --- a/src/main/java/org/owasp/esapi/reference/accesscontrol/ExperimentalAccessController.java +++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/ExperimentalAccessController.java @@ -11,184 +11,184 @@ import org.owasp.esapi.reference.accesscontrol.policyloader.PolicyDTO; public class ExperimentalAccessController implements AccessController { - private Map ruleMap; + private Map ruleMap; - protected final Logger logger = ESAPI.getLogger("DefaultAccessController"); - - public ExperimentalAccessController(Map ruleMap) { - this.ruleMap = ruleMap; - } - public ExperimentalAccessController() throws AccessControlException { - ACRPolicyFileLoader policyDescriptor = new ACRPolicyFileLoader(); - PolicyDTO policyDTO = policyDescriptor.load(); - ruleMap = policyDTO.getAccessControlRules(); - } - - public boolean isAuthorized(Object key, Object runtimeParameter) { - try { - AccessControlRule rule = (AccessControlRule)ruleMap.get(key); - if(rule == null) { - throw new AccessControlException("Access Denied", - "AccessControlRule was not found for key: " + key); - } - if(logger.isDebugEnabled()){ logger.debug(Logger.EVENT_SUCCESS, "Evaluating Authorization Rule \"" + key + "\" Using class: " + rule.getClass().getCanonicalName()); } - return rule.isAuthorized(runtimeParameter); - } catch(Exception e) { - try { - //Log the exception by throwing and then catching it. - //TODO figure out what which string goes where. - throw new AccessControlException("Access Denied", - "An unhandled Exception was " + - "caught, so access is denied.", - e); - } catch(AccessControlException ace) { - //the exception was just logged. There's nothing left to do. - } - return false; //fail closed - } - } + protected final Logger logger = ESAPI.getLogger("DefaultAccessController"); + + public ExperimentalAccessController(Map ruleMap) { + this.ruleMap = ruleMap; + } + public ExperimentalAccessController() throws AccessControlException { + ACRPolicyFileLoader policyDescriptor = new ACRPolicyFileLoader(); + PolicyDTO policyDTO = policyDescriptor.load(); + ruleMap = policyDTO.getAccessControlRules(); + } + + public boolean isAuthorized(Object key, Object runtimeParameter) { + try { + AccessControlRule rule = (AccessControlRule)ruleMap.get(key); + if(rule == null) { + throw new AccessControlException("Access Denied", + "AccessControlRule was not found for key: " + key); + } + if(logger.isDebugEnabled()){ logger.debug(Logger.EVENT_SUCCESS, "Evaluating Authorization Rule \"" + key + "\" Using class: " + rule.getClass().getCanonicalName()); } + return rule.isAuthorized(runtimeParameter); + } catch(Exception e) { + try { + //Log the exception by throwing and then catching it. + //TODO figure out what which string goes where. + throw new AccessControlException("Access Denied", + "An unhandled Exception was " + + "caught, so access is denied.", + e); + } catch(AccessControlException ace) { + //the exception was just logged. There's nothing left to do. + } + return false; //fail closed + } + } - public void assertAuthorized(Object key, Object runtimeParameter) - throws AccessControlException { - boolean isAuthorized = false; - try { - AccessControlRule rule = (AccessControlRule)ruleMap.get(key); - if(rule == null) { - throw new AccessControlException("Access Denied", - "AccessControlRule was not found for key: " + key); - } - if(logger.isDebugEnabled()){ logger.debug(Logger.EVENT_SUCCESS, "Asserting Authorization Rule \"" + key + "\" Using class: " + rule.getClass().getCanonicalName()); } - isAuthorized = rule.isAuthorized(runtimeParameter); - } catch(Exception e) { - //TODO figure out what which string goes where. - throw new AccessControlException("Access Denied", "An unhandled Exception was " + - "caught, so access is denied." + - "AccessControlException.", - e); - } - if(!isAuthorized) { - throw new AccessControlException("Access Denied", - "Access Denied for key: " + key + - " runtimeParameter: " + runtimeParameter); - } - } - - /**** Below this line is legacy support ****/ - - /** - * @param action - * @param data - * @throws AccessControlException - * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForData(java.lang.String, java.lang.Object) - * @deprecated - */ + public void assertAuthorized(Object key, Object runtimeParameter) + throws AccessControlException { + boolean isAuthorized = false; + try { + AccessControlRule rule = (AccessControlRule)ruleMap.get(key); + if(rule == null) { + throw new AccessControlException("Access Denied", + "AccessControlRule was not found for key: " + key); + } + if(logger.isDebugEnabled()){ logger.debug(Logger.EVENT_SUCCESS, "Asserting Authorization Rule \"" + key + "\" Using class: " + rule.getClass().getCanonicalName()); } + isAuthorized = rule.isAuthorized(runtimeParameter); + } catch(Exception e) { + //TODO figure out what which string goes where. + throw new AccessControlException("Access Denied", "An unhandled Exception was " + + "caught, so access is denied." + + "AccessControlException.", + e); + } + if(!isAuthorized) { + throw new AccessControlException("Access Denied", + "Access Denied for key: " + key + + " runtimeParameter: " + runtimeParameter); + } + } + + /**** Below this line is legacy support ****/ + + /** + * @param action + * @param data + * @throws AccessControlException + * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForData(java.lang.String, java.lang.Object) + * @deprecated + */ @Deprecated - public void assertAuthorizedForData(String action, Object data) - throws AccessControlException { - this.assertAuthorized("AC 1.0 Data", new Object[] {action, data}); - } + public void assertAuthorizedForData(String action, Object data) + throws AccessControlException { + this.assertAuthorized("AC 1.0 Data", new Object[] {action, data}); + } - /** - * @param filepath - * @throws AccessControlException - * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForFile(java.lang.String) - * @deprecated - */ + /** + * @param filepath + * @throws AccessControlException + * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForFile(java.lang.String) + * @deprecated + */ @Deprecated - public void assertAuthorizedForFile(String filepath) - throws AccessControlException { - this.assertAuthorized("AC 1.0 File", new Object[] {filepath}); - } + public void assertAuthorizedForFile(String filepath) + throws AccessControlException { + this.assertAuthorized("AC 1.0 File", new Object[] {filepath}); + } - /** - * @param functionName - * @throws AccessControlException - * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForFunction(java.lang.String) - * @deprecated - */ + /** + * @param functionName + * @throws AccessControlException + * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForFunction(java.lang.String) + * @deprecated + */ @Deprecated - public void assertAuthorizedForFunction(String functionName) - throws AccessControlException { - this.assertAuthorized("AC 1.0 Function", new Object[] {functionName}); - } + public void assertAuthorizedForFunction(String functionName) + throws AccessControlException { + this.assertAuthorized("AC 1.0 Function", new Object[] {functionName}); + } - /** - * @param serviceName - * @throws AccessControlException - * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForService(java.lang.String) - * @deprecated - */ + /** + * @param serviceName + * @throws AccessControlException + * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForService(java.lang.String) + * @deprecated + */ @Deprecated - public void assertAuthorizedForService(String serviceName) - throws AccessControlException { - this.assertAuthorized("AC 1.0 Service", new Object[] {serviceName}); - } + public void assertAuthorizedForService(String serviceName) + throws AccessControlException { + this.assertAuthorized("AC 1.0 Service", new Object[] {serviceName}); + } - /** - * @param url - * @throws AccessControlException - * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForURL(java.lang.String) - * @deprecated - */ + /** + * @param url + * @throws AccessControlException + * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForURL(java.lang.String) + * @deprecated + */ @Deprecated - public void assertAuthorizedForURL(String url) - throws AccessControlException { - this.assertAuthorized("AC 1.0 URL", new Object[] {url}); - } + public void assertAuthorizedForURL(String url) + throws AccessControlException { + this.assertAuthorized("AC 1.0 URL", new Object[] {url}); + } - /** - * @param action - * @param data - * @return {@code true} if access is permitted; {@code false} otherwise. - * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForData(java.lang.String, java.lang.Object) - * @deprecated - */ + /** + * @param action + * @param data + * @return {@code true} if access is permitted; {@code false} otherwise. + * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForData(java.lang.String, java.lang.Object) + * @deprecated + */ @Deprecated - public boolean isAuthorizedForData(String action, Object data) { - return this.isAuthorized("AC 1.0 Data", new Object[] {action, data}); - } + public boolean isAuthorizedForData(String action, Object data) { + return this.isAuthorized("AC 1.0 Data", new Object[] {action, data}); + } - /** - * @param filepath + /** + * @param filepath * @return {@code true} if access is permitted; {@code false} otherwise. - * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForFile(java.lang.String) - * @deprecated - */ + * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForFile(java.lang.String) + * @deprecated + */ @Deprecated - public boolean isAuthorizedForFile(String filepath) { - return this.isAuthorized("AC 1.0 File", new Object[] {filepath}); - } + public boolean isAuthorizedForFile(String filepath) { + return this.isAuthorized("AC 1.0 File", new Object[] {filepath}); + } - /** - * @param functionName + /** + * @param functionName * @return {@code true} if access is permitted; {@code false} otherwise. - * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForFunction(java.lang.String) - * @deprecated - */ + * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForFunction(java.lang.String) + * @deprecated + */ @Deprecated - public boolean isAuthorizedForFunction(String functionName) { - return this.isAuthorized("AC 1.0 Function", new Object[] {functionName}); - } + public boolean isAuthorizedForFunction(String functionName) { + return this.isAuthorized("AC 1.0 Function", new Object[] {functionName}); + } - /** - * @param serviceName + /** + * @param serviceName * @return {@code true} if access is permitted; {@code false} otherwise. - * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForService(java.lang.String) - * @deprecated - */ + * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForService(java.lang.String) + * @deprecated + */ @Deprecated - public boolean isAuthorizedForService(String serviceName) { - return this.isAuthorized("AC 1.0 Service", new Object[] {serviceName}); - } + public boolean isAuthorizedForService(String serviceName) { + return this.isAuthorized("AC 1.0 Service", new Object[] {serviceName}); + } - /** - * @param url + /** + * @param url * @return {@code true} if access is permitted; {@code false} otherwise. - * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForURL(java.lang.String) - * @deprecated - */ + * @see org.owasp.esapi.reference.accesscontrol.FileBasedACRs#isAuthorizedForURL(java.lang.String) + * @deprecated + */ @Deprecated - public boolean isAuthorizedForURL(String url) { - return this.isAuthorized("AC 1.0 URL", new Object[] {url}); - } + public boolean isAuthorizedForURL(String url) { + return this.isAuthorized("AC 1.0 URL", new Object[] {url}); + } } diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/FileBasedACRs.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/FileBasedACRs.java index 0e2d8fe3e..8562beb35 100644 --- a/src/main/java/org/owasp/esapi/reference/accesscontrol/FileBasedACRs.java +++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/FileBasedACRs.java @@ -104,456 +104,456 @@ */ public class FileBasedACRs { - /** The url map. */ - private Map urlMap = new HashMap(); + /** The url map. */ + private Map urlMap = new HashMap(); - /** The function map. */ - private Map functionMap = new HashMap(); + /** The function map. */ + private Map functionMap = new HashMap(); - /** The data map. */ - private Map dataMap = new HashMap(); + /** The data map. */ + private Map dataMap = new HashMap(); - /** The file map. */ - private Map fileMap = new HashMap(); + /** The file map. */ + private Map fileMap = new HashMap(); - /** The service map. */ - private Map serviceMap = new HashMap(); + /** The service map. */ + private Map serviceMap = new HashMap(); - /** A rule containing "deny". */ - private Rule deny = new Rule(); + /** A rule containing "deny". */ + private Rule deny = new Rule(); - /** The logger. */ - private Logger logger = ESAPI.getLogger("FileBasedACRs"); + /** The logger. */ + private Logger logger = ESAPI.getLogger("FileBasedACRs"); /** - * Check if URL is authorized. - * @param url The URL tested for authorization - * @return {@code true} if access is allowed, {@code false} otherwise. - */ + * Check if URL is authorized. + * @param url The URL tested for authorization + * @return {@code true} if access is allowed, {@code false} otherwise. + */ public boolean isAuthorizedForURL(String url) { - if (urlMap==null || urlMap.isEmpty()) { - urlMap = loadRules("URLAccessRules.txt"); - } - return matchRule(urlMap, url); - } + if (urlMap==null || urlMap.isEmpty()) { + urlMap = loadRules("URLAccessRules.txt"); + } + return matchRule(urlMap, url); + } /** - * TODO Javadoc - */ + * TODO Javadoc + */ public boolean isAuthorizedForFunction(String functionName) throws AccessControlException { - if (functionMap==null || functionMap.isEmpty()) { - functionMap = loadRules("FunctionAccessRules.txt"); - } - return matchRule(functionMap, functionName); - } + if (functionMap==null || functionMap.isEmpty()) { + functionMap = loadRules("FunctionAccessRules.txt"); + } + return matchRule(functionMap, functionName); + } /** - * TODO Javadoc - */ + * TODO Javadoc + */ public boolean isAuthorizedForData(String action, Object data) throws AccessControlException{ - if (dataMap==null || dataMap.isEmpty()) { - dataMap = loadDataRules("DataAccessRules.txt"); - } - return matchRule(dataMap, (Class)data, action); + if (dataMap==null || dataMap.isEmpty()) { + dataMap = loadDataRules("DataAccessRules.txt"); + } + return matchRule(dataMap, (Class)data, action); } /** - * TODO Javadoc - */ + * TODO Javadoc + */ public boolean isAuthorizedForFile(String filepath) throws AccessControlException { - if (fileMap==null || fileMap.isEmpty()) { - fileMap = loadRules("FileAccessRules.txt"); - } - return matchRule(fileMap, filepath.replaceAll("\\\\","/")); - } + if (fileMap==null || fileMap.isEmpty()) { + fileMap = loadRules("FileAccessRules.txt"); + } + return matchRule(fileMap, filepath.replaceAll("\\\\","/")); + } + + /** + * TODO Javadoc + */ + public boolean isAuthorizedForService(String serviceName) throws AccessControlException { + if (serviceMap==null || serviceMap.isEmpty()) { + serviceMap = loadRules("ServiceAccessRules.txt"); + } + return matchRule(serviceMap, serviceName); + } /** - * TODO Javadoc - */ - public boolean isAuthorizedForService(String serviceName) throws AccessControlException { - if (serviceMap==null || serviceMap.isEmpty()) { - serviceMap = loadRules("ServiceAccessRules.txt"); - } - return matchRule(serviceMap, serviceName); - } - - /** - * Checks to see if the current user has access to the specified data, File, Object, etc. - * If the User has access, as specified by the map parameter, this method returns true. If the - * User does not have access or an exception is thrown, false is returned. - * - * @param map - * the map containing access rules - * @param path - * the path of the requested File, URL, Object, etc. - * - * @return - * true, if the user has access, false otherwise - * - */ - private boolean matchRule(Map map, String path) { - // get users roles - User user = ESAPI.authenticator().getCurrentUser(); - Set roles = user.getRoles(); - // search for the first rule that matches the path and rules - Rule rule = searchForRule(map, roles, path); - return rule.allow; - } - - /** - * Checks to see if the current user has access to the specified Class and action. - * If the User has access, as specified by the map parameter, this method returns true. + * Checks to see if the current user has access to the specified data, File, Object, etc. + * If the User has access, as specified by the map parameter, this method returns true. If the + * User does not have access or an exception is thrown, false is returned. + * + * @param map + * the map containing access rules + * @param path + * the path of the requested File, URL, Object, etc. + * + * @return + * true, if the user has access, false otherwise + * + */ + private boolean matchRule(Map map, String path) { + // get users roles + User user = ESAPI.authenticator().getCurrentUser(); + Set roles = user.getRoles(); + // search for the first rule that matches the path and rules + Rule rule = searchForRule(map, roles, path); + return rule.allow; + } + + /** + * Checks to see if the current user has access to the specified Class and action. + * If the User has access, as specified by the map parameter, this method returns true. * If the User does not have access or an exception is thrown, false is returned. - * - * @param map - * the map containing access rules - * @param clazz - * the Class being requested for access - * @param action - * the action the User has asked to perform - * @return - * true, if the user has access, false otherwise - * - */ - private boolean matchRule(Map map, Class clazz, String action) { - // get users roles - User user = ESAPI.authenticator().getCurrentUser(); - Set roles = user.getRoles(); - // search for the first rule that matches the path and rules - Rule rule = searchForRule(map, roles, clazz, action); - return rule != null; - } - - /** - * Search for rule. Four mapping rules are used in order: - exact match, - * e.g. /access/login - longest path prefix match, beginning / and ending - * /*, e.g. /access/* or /* - extension match, beginning *., e.g. *.css - - * default servlet, specified by the single character pattern / - * - * @param map - * the map containing access rules - * @param roles - * the roles of the User being checked for access - * @param path - * the File, URL, Object, etc. being checked for access - * - * @return - * the rule stating whether to allow or deny access - * - */ - private Rule searchForRule(Map map, Set roles, String path) { - String canonical = ESAPI.encoder().canonicalize(path); - - String part = canonical; + * + * @param map + * the map containing access rules + * @param clazz + * the Class being requested for access + * @param action + * the action the User has asked to perform + * @return + * true, if the user has access, false otherwise + * + */ + private boolean matchRule(Map map, Class clazz, String action) { + // get users roles + User user = ESAPI.authenticator().getCurrentUser(); + Set roles = user.getRoles(); + // search for the first rule that matches the path and rules + Rule rule = searchForRule(map, roles, clazz, action); + return rule != null; + } + + /** + * Search for rule. Four mapping rules are used in order: - exact match, + * e.g. /access/login - longest path prefix match, beginning / and ending + * /*, e.g. /access/* or /* - extension match, beginning *., e.g. *.css - + * default servlet, specified by the single character pattern / + * + * @param map + * the map containing access rules + * @param roles + * the roles of the User being checked for access + * @param path + * the File, URL, Object, etc. being checked for access + * + * @return + * the rule stating whether to allow or deny access + * + */ + private Rule searchForRule(Map map, Set roles, String path) { + String canonical = ESAPI.encoder().canonicalize(path); + + String part = canonical; if ( part == null ) { part = ""; } - while (part.endsWith("/")) { - part = part.substring(0, part.length() - 1); - } - - if (part.indexOf("..") != -1) { - throw new IntrusionException("Attempt to manipulate access control path", "Attempt to manipulate access control path: " + path ); - } - - // extract extension if any - String extension = ""; - int extIndex = part.lastIndexOf("."); - if (extIndex != -1) { - extension = part.substring(extIndex + 1); - } - - // Check for exact match - ignore any ending slash - Rule rule = (Rule) map.get(part); - - // Check for ending with /* - if (rule == null) - rule = (Rule) map.get(part + "/*"); - - // Check for matching extension rule *.ext - if (rule == null) - rule = (Rule) map.get("*." + extension); - - // if rule found and user's roles match rules' roles, return the rule - if (rule != null && overlap(rule.roles, roles)) - return rule; - - // rule hasn't been found - if there are no more parts, return a deny - int slash = part.lastIndexOf('/'); - if ( slash == -1 ) { - return deny; - } - - // if there are more parts, strip off the last part and recurse - part = part.substring(0, part.lastIndexOf('/')); - - // return default deny - if (part.length() <= 1) { - return deny; - } - - return searchForRule(map, roles, part); - } - - /** - * Search for rule. Searches the specified access map to see if any of the roles specified have - * access to perform the specified action on the specified Class. - * - * @param map - * the map containing access rules - * @param roles - * the roles used to determine access level - * @param clazz - * the Class being requested for access - * @param action - * the action the User has asked to perform - * - * @return - * the rule that allows the specified roles access to perform the requested action on the specified Class, or null if access is not granted - * - */ - private Rule searchForRule(Map map, Set roles, Class clazz, String action) { - - // Check for exact match - ignore any ending slash - Rule rule = (Rule) map.get(clazz); - if( ( rule != null ) && ( overlap(rule.actions, action) ) && ( overlap(rule.roles, roles) )){ - return rule; - } - return null; - } - - /** - * Return true if there is overlap between the two sets. This method merely checks to see if - * ruleRoles contains any of the roles listed in userRoles. - * - * @param ruleRoles - * the rule roles - * @param userRoles - * the user roles - * - * @return - * true, if any roles exist in both Sets. False otherwise. - */ - private boolean overlap(Set ruleRoles, Set userRoles) { - if (ruleRoles.contains("any")) { - return true; - } - Iterator i = userRoles.iterator(); - while (i.hasNext()) { - String role = (String) i.next(); - if (ruleRoles.contains(role)) { - return true; - } - } - return false; - } - - /** - * This method merely checks to see if ruleActions contains the action requested. - * - * @param ruleActions - * actions listed for a rule - * @param action - * the action requested that will be searched for in ruleActions - * - * @return - * true, if any action exists in ruleActions. False otherwise. - */ - private boolean overlap( List ruleActions, String action){ - if( ruleActions.contains(action) ) - return true; - return false; - } - - /** - * Checks that the roles passed in contain only letters, numbers, and underscores. Also checks that - * roles are no more than 10 characters long. If a role does not pass validation, it is not included in the - * list of roles returned by this method. A log warning is also generated for any invalid roles. - * - * @param roles - * roles to validate according to criteria started above - * @return - * a List of roles that are valid according to the criteria stated above. - * - */ - private List validateRoles(List roles){ - List ret = new ArrayList(); - for(int x = 0; x < roles.size(); x++){ - String canonical = ESAPI.encoder().canonicalize(((String)roles.get(x)).trim()); - - if(!ESAPI.validator().isValidInput("Validating user roles in FileBasedAccessController", canonical, "RoleName", 20, false)) { - logger.warning( Logger.SECURITY_FAILURE, "Role: " + ((String)roles.get(x)).trim() + " is invalid, so was not added to the list of roles for this Rule."); - } else { - ret.add(canonical.trim()); - } - } - return ret; - } - - /** - * Loads access rules by storing them in a hashmap. This method begins reading the File specified by - * the ruleset parameter, ignoring any lines that begin with '#' characters as comments. Sections of the access rules file - * are split by the pipe character ('|'). The method loads all paths, replacing '\' characters with '/' for uniformity then loads - * the list of comma separated roles. The roles are validated to be sure they are within a - * length and character set, specified in the validateRoles(String) method. Then the permissions are stored for each item in the rules list. - * If the word "allow" appears on the line, the specified roles are granted access to the data - otherwise, they will be denied access. - * - * Each path may only appear once in the access rules file. Any entry, after the first, containing the same path will be logged and ignored. - * - * @param ruleset - * the name of the data that contains access rules - * - * @return - * a hash map containing the ruleset - */ - private Map loadRules(String ruleset) { - ruleset = "fbac-policies/" + ruleset; - Map map = new HashMap(); - InputStream is = null; - try { - is = ESAPI.securityConfiguration().getResourceStream(ruleset); - String line = ""; - while ((line = ESAPI.validator().safeReadLine(is, 500)) != null) { - if (line.length() > 0 && line.charAt(0) != '#') { - Rule rule = new Rule(); - String[] parts = line.split("\\|"); - // fix Windows paths - rule.path = parts[0].trim().replaceAll("\\\\", "/"); - - List roles = commaSplit(parts[1].trim().toLowerCase()); - roles = validateRoles(roles); - for(int x = 0; x < roles.size(); x++) - rule.roles.add(((String)roles.get(x)).trim()); - - String action = parts[2].trim(); - rule.allow = action.equalsIgnoreCase("allow"); - if (map.containsKey(rule.path)) { - logger.warning( Logger.SECURITY_FAILURE, "Problem in access control file. Duplicate rule ignored: " + rule); - } else { - map.put(rule.path, rule); - } - } - } - } catch (Exception e) { - logger.warning( Logger.SECURITY_FAILURE, "Problem in access control file: " + ruleset, e ); - } finally { - try { - if (is != null) { - is.close(); - } - } catch (IOException e) { - logger.warning(Logger.SECURITY_FAILURE, "Failure closing access control file: " + ruleset, e); - } - } - return map; - } - - /** - * Loads access rules by storing them in a hashmap. This method begins reading the File specified by - * the ruleset parameter, ignoring any lines that begin with '#' characters as comments. Sections of the access rules file - * are split by the pipe character ('|'). The method then loads all Classes, loads the list of comma separated roles, then the list of comma separated actions. - * The roles are validated to be sure they are within a length and character set, specified in the validateRoles(String) method. - * - * Each path may only appear once in the access rules file. Any entry, after the first, containing the same path will be logged and ignored. - * - * @param ruleset - * the name of the data that contains access rules - * - * @return - * a hash map containing the ruleset - */ - private Map loadDataRules(String ruleset) { - Map map = new HashMap(); - InputStream is = null; - - try { - ruleset = "fbac-policies/" + ruleset; - is = ESAPI.securityConfiguration().getResourceStream(ruleset); - String line = ""; - while ((line = ESAPI.validator().safeReadLine(is, 500)) != null) { - if (line.length() > 0 && line.charAt(0) != '#') { - Rule rule = new Rule(); - String[] parts = line.split("\\|"); - rule.clazz = Class.forName(parts[0].trim()); - - List roles = commaSplit(parts[1].trim().toLowerCase()); - roles = validateRoles(roles); - for(int x = 0; x < roles.size(); x++) - rule.roles.add(((String)roles.get(x)).trim()); - - List action = commaSplit(parts[2].trim().toLowerCase()); - for(int x = 0; x < action.size(); x++) - rule.actions.add(((String) action.get(x)).trim()); - - if (map.containsKey(rule.path)) { - logger.warning( Logger.SECURITY_FAILURE, "Problem in access control file. Duplicate rule ignored: " + rule); - } else { - map.put(rule.clazz, rule); - } - } - } - } catch (Exception e) { - logger.warning( Logger.SECURITY_FAILURE, "Problem in access control file : " + ruleset, e ); - } finally { - - try { - if (is != null) { - is.close(); - } - } catch (IOException e) { - logger.warning(Logger.SECURITY_FAILURE, "Failure closing access control file : " + ruleset, e); - } - } - return map; - } - - /** - * This method splits a String by the ',' and returns the result as a List. - * - * @param input - * the String to split by ',' - * @return - * a List where each entry was on either side of a ',' in the original String - */ - private List commaSplit(String input){ - String[] array = input.split(","); - return Arrays.asList(array); - } - - /** - * The Class Rule. - */ - private class Rule { - - - protected String path = ""; - - - protected Set roles = new HashSet(); - - - protected boolean allow = false; - - - protected Class clazz = null; - - - protected List actions = new ArrayList(); - - /** - * - * Creates a new Rule object. - */ - protected Rule() { - // to replace synthetic accessor method - } - - /** - * {@inheritDoc} - */ - public String toString() { - return "URL:" + path + " | " + roles + " | " + (allow ? "allow" : "deny"); - } - } + while (part.endsWith("/")) { + part = part.substring(0, part.length() - 1); + } + + if (part.indexOf("..") != -1) { + throw new IntrusionException("Attempt to manipulate access control path", "Attempt to manipulate access control path: " + path ); + } + + // extract extension if any + String extension = ""; + int extIndex = part.lastIndexOf("."); + if (extIndex != -1) { + extension = part.substring(extIndex + 1); + } + + // Check for exact match - ignore any ending slash + Rule rule = (Rule) map.get(part); + + // Check for ending with /* + if (rule == null) + rule = (Rule) map.get(part + "/*"); + + // Check for matching extension rule *.ext + if (rule == null) + rule = (Rule) map.get("*." + extension); + + // if rule found and user's roles match rules' roles, return the rule + if (rule != null && overlap(rule.roles, roles)) + return rule; + + // rule hasn't been found - if there are no more parts, return a deny + int slash = part.lastIndexOf('/'); + if ( slash == -1 ) { + return deny; + } + + // if there are more parts, strip off the last part and recurse + part = part.substring(0, part.lastIndexOf('/')); + + // return default deny + if (part.length() <= 1) { + return deny; + } + + return searchForRule(map, roles, part); + } + + /** + * Search for rule. Searches the specified access map to see if any of the roles specified have + * access to perform the specified action on the specified Class. + * + * @param map + * the map containing access rules + * @param roles + * the roles used to determine access level + * @param clazz + * the Class being requested for access + * @param action + * the action the User has asked to perform + * + * @return + * the rule that allows the specified roles access to perform the requested action on the specified Class, or null if access is not granted + * + */ + private Rule searchForRule(Map map, Set roles, Class clazz, String action) { + + // Check for exact match - ignore any ending slash + Rule rule = (Rule) map.get(clazz); + if( ( rule != null ) && ( overlap(rule.actions, action) ) && ( overlap(rule.roles, roles) )){ + return rule; + } + return null; + } + + /** + * Return true if there is overlap between the two sets. This method merely checks to see if + * ruleRoles contains any of the roles listed in userRoles. + * + * @param ruleRoles + * the rule roles + * @param userRoles + * the user roles + * + * @return + * true, if any roles exist in both Sets. False otherwise. + */ + private boolean overlap(Set ruleRoles, Set userRoles) { + if (ruleRoles.contains("any")) { + return true; + } + Iterator i = userRoles.iterator(); + while (i.hasNext()) { + String role = (String) i.next(); + if (ruleRoles.contains(role)) { + return true; + } + } + return false; + } + + /** + * This method merely checks to see if ruleActions contains the action requested. + * + * @param ruleActions + * actions listed for a rule + * @param action + * the action requested that will be searched for in ruleActions + * + * @return + * true, if any action exists in ruleActions. False otherwise. + */ + private boolean overlap( List ruleActions, String action){ + if( ruleActions.contains(action) ) + return true; + return false; + } + + /** + * Checks that the roles passed in contain only letters, numbers, and underscores. Also checks that + * roles are no more than 10 characters long. If a role does not pass validation, it is not included in the + * list of roles returned by this method. A log warning is also generated for any invalid roles. + * + * @param roles + * roles to validate according to criteria started above + * @return + * a List of roles that are valid according to the criteria stated above. + * + */ + private List validateRoles(List roles){ + List ret = new ArrayList(); + for(int x = 0; x < roles.size(); x++){ + String canonical = ESAPI.encoder().canonicalize(((String)roles.get(x)).trim()); + + if(!ESAPI.validator().isValidInput("Validating user roles in FileBasedAccessController", canonical, "RoleName", 20, false)) { + logger.warning( Logger.SECURITY_FAILURE, "Role: " + ((String)roles.get(x)).trim() + " is invalid, so was not added to the list of roles for this Rule."); + } else { + ret.add(canonical.trim()); + } + } + return ret; + } + + /** + * Loads access rules by storing them in a hashmap. This method begins reading the File specified by + * the ruleset parameter, ignoring any lines that begin with '#' characters as comments. Sections of the access rules file + * are split by the pipe character ('|'). The method loads all paths, replacing '\' characters with '/' for uniformity then loads + * the list of comma separated roles. The roles are validated to be sure they are within a + * length and character set, specified in the validateRoles(String) method. Then the permissions are stored for each item in the rules list. + * If the word "allow" appears on the line, the specified roles are granted access to the data - otherwise, they will be denied access. + * + * Each path may only appear once in the access rules file. Any entry, after the first, containing the same path will be logged and ignored. + * + * @param ruleset + * the name of the data that contains access rules + * + * @return + * a hash map containing the ruleset + */ + private Map loadRules(String ruleset) { + ruleset = "fbac-policies/" + ruleset; + Map map = new HashMap(); + InputStream is = null; + try { + is = ESAPI.securityConfiguration().getResourceStream(ruleset); + String line = ""; + while ((line = ESAPI.validator().safeReadLine(is, 500)) != null) { + if (line.length() > 0 && line.charAt(0) != '#') { + Rule rule = new Rule(); + String[] parts = line.split("\\|"); + // fix Windows paths + rule.path = parts[0].trim().replaceAll("\\\\", "/"); + + List roles = commaSplit(parts[1].trim().toLowerCase()); + roles = validateRoles(roles); + for(int x = 0; x < roles.size(); x++) + rule.roles.add(((String)roles.get(x)).trim()); + + String action = parts[2].trim(); + rule.allow = action.equalsIgnoreCase("allow"); + if (map.containsKey(rule.path)) { + logger.warning( Logger.SECURITY_FAILURE, "Problem in access control file. Duplicate rule ignored: " + rule); + } else { + map.put(rule.path, rule); + } + } + } + } catch (Exception e) { + logger.warning( Logger.SECURITY_FAILURE, "Problem in access control file: " + ruleset, e ); + } finally { + try { + if (is != null) { + is.close(); + } + } catch (IOException e) { + logger.warning(Logger.SECURITY_FAILURE, "Failure closing access control file: " + ruleset, e); + } + } + return map; + } + + /** + * Loads access rules by storing them in a hashmap. This method begins reading the File specified by + * the ruleset parameter, ignoring any lines that begin with '#' characters as comments. Sections of the access rules file + * are split by the pipe character ('|'). The method then loads all Classes, loads the list of comma separated roles, then the list of comma separated actions. + * The roles are validated to be sure they are within a length and character set, specified in the validateRoles(String) method. + * + * Each path may only appear once in the access rules file. Any entry, after the first, containing the same path will be logged and ignored. + * + * @param ruleset + * the name of the data that contains access rules + * + * @return + * a hash map containing the ruleset + */ + private Map loadDataRules(String ruleset) { + Map map = new HashMap(); + InputStream is = null; + + try { + ruleset = "fbac-policies/" + ruleset; + is = ESAPI.securityConfiguration().getResourceStream(ruleset); + String line = ""; + while ((line = ESAPI.validator().safeReadLine(is, 500)) != null) { + if (line.length() > 0 && line.charAt(0) != '#') { + Rule rule = new Rule(); + String[] parts = line.split("\\|"); + rule.clazz = Class.forName(parts[0].trim()); + + List roles = commaSplit(parts[1].trim().toLowerCase()); + roles = validateRoles(roles); + for(int x = 0; x < roles.size(); x++) + rule.roles.add(((String)roles.get(x)).trim()); + + List action = commaSplit(parts[2].trim().toLowerCase()); + for(int x = 0; x < action.size(); x++) + rule.actions.add(((String) action.get(x)).trim()); + + if (map.containsKey(rule.path)) { + logger.warning( Logger.SECURITY_FAILURE, "Problem in access control file. Duplicate rule ignored: " + rule); + } else { + map.put(rule.clazz, rule); + } + } + } + } catch (Exception e) { + logger.warning( Logger.SECURITY_FAILURE, "Problem in access control file : " + ruleset, e ); + } finally { + + try { + if (is != null) { + is.close(); + } + } catch (IOException e) { + logger.warning(Logger.SECURITY_FAILURE, "Failure closing access control file : " + ruleset, e); + } + } + return map; + } + + /** + * This method splits a String by the ',' and returns the result as a List. + * + * @param input + * the String to split by ',' + * @return + * a List where each entry was on either side of a ',' in the original String + */ + private List commaSplit(String input){ + String[] array = input.split(","); + return Arrays.asList(array); + } + + /** + * The Class Rule. + */ + private class Rule { + + + protected String path = ""; + + + protected Set roles = new HashSet(); + + + protected boolean allow = false; + + + protected Class clazz = null; + + + protected List actions = new ArrayList(); + + /** + * + * Creates a new Rule object. + */ + protected Rule() { + // to replace synthetic accessor method + } + + /** + * {@inheritDoc} + */ + public String toString() { + return "URL:" + path + " | " + roles + " | " + (allow ? "allow" : "deny"); + } + } } diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRParameterLoader.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRParameterLoader.java index c4456619c..a0ae77f95 100644 --- a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRParameterLoader.java +++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRParameterLoader.java @@ -4,6 +4,6 @@ public interface ACRParameterLoader { - public abstract T getParameters(XMLConfiguration config, int currentRule) - throws java.lang.Exception; //TODO this exception could be more specific + public abstract T getParameters(XMLConfiguration config, int currentRule) + throws java.lang.Exception; //TODO this exception could be more specific } diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRParameterLoaderHelper.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRParameterLoaderHelper.java index 22be7f0f3..cc17bdbe0 100644 --- a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRParameterLoaderHelper.java +++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRParameterLoaderHelper.java @@ -3,44 +3,44 @@ import org.apache.commons.configuration.XMLConfiguration; final public class ACRParameterLoaderHelper { - - public static Object getParameterValue(XMLConfiguration config, int currentRule, int currentParameter, String parameterType) throws Exception { - String key = "AccessControlRules.AccessControlRule(" + - currentRule + ").Parameters.Parameter(" + currentParameter + ")[@value]"; - Object parameterValue; - if("String".equalsIgnoreCase(parameterType)) { - parameterValue = config.getString(key); - } else if("StringArray".equalsIgnoreCase(parameterType)) { - parameterValue = config.getStringArray(key); - } else if("Boolean".equalsIgnoreCase(parameterType)){ - parameterValue = config.getBoolean(key); - } else if("Byte".equalsIgnoreCase(parameterType)){ - parameterValue = config.getByte(key); - } else if("Int".equalsIgnoreCase(parameterType)){ - parameterValue = config.getInt(key); - } else if("Long".equalsIgnoreCase(parameterType)){ - parameterValue = config.getLong(key); - } else if("Float".equalsIgnoreCase(parameterType)){ - parameterValue = config.getFloat(key); - } else if("Double".equalsIgnoreCase(parameterType)){ - parameterValue = config.getDouble(key); - } else if("BigDecimal".equalsIgnoreCase(parameterType)){ - parameterValue = config.getBigDecimal(key); - } else if("BigInteger".equalsIgnoreCase(parameterType)){ - parameterValue = config.getBigInteger(key); - } else if("Date".equalsIgnoreCase(parameterType)){ - parameterValue = java.text.DateFormat.getDateInstance().parse(config.getString(key)); - } else if("Time".equalsIgnoreCase(parameterType)){ - java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("h:mm a"); - parameterValue = sdf.parseObject(config.getString(key)); -// parameterValue = java.text.DateFormat.getTimeInstance().parse(config.getString(key)); - } - //add timestamp. check for other stuff. - else { - throw new IllegalArgumentException("Unable to load the key \"" + key - + "\", because " + "the type \"" + parameterType + - "\" was not recognized." ); - } - return parameterValue; - } + + public static Object getParameterValue(XMLConfiguration config, int currentRule, int currentParameter, String parameterType) throws Exception { + String key = "AccessControlRules.AccessControlRule(" + + currentRule + ").Parameters.Parameter(" + currentParameter + ")[@value]"; + Object parameterValue; + if("String".equalsIgnoreCase(parameterType)) { + parameterValue = config.getString(key); + } else if("StringArray".equalsIgnoreCase(parameterType)) { + parameterValue = config.getStringArray(key); + } else if("Boolean".equalsIgnoreCase(parameterType)){ + parameterValue = config.getBoolean(key); + } else if("Byte".equalsIgnoreCase(parameterType)){ + parameterValue = config.getByte(key); + } else if("Int".equalsIgnoreCase(parameterType)){ + parameterValue = config.getInt(key); + } else if("Long".equalsIgnoreCase(parameterType)){ + parameterValue = config.getLong(key); + } else if("Float".equalsIgnoreCase(parameterType)){ + parameterValue = config.getFloat(key); + } else if("Double".equalsIgnoreCase(parameterType)){ + parameterValue = config.getDouble(key); + } else if("BigDecimal".equalsIgnoreCase(parameterType)){ + parameterValue = config.getBigDecimal(key); + } else if("BigInteger".equalsIgnoreCase(parameterType)){ + parameterValue = config.getBigInteger(key); + } else if("Date".equalsIgnoreCase(parameterType)){ + parameterValue = java.text.DateFormat.getDateInstance().parse(config.getString(key)); + } else if("Time".equalsIgnoreCase(parameterType)){ + java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("h:mm a"); + parameterValue = sdf.parseObject(config.getString(key)); +// parameterValue = java.text.DateFormat.getTimeInstance().parse(config.getString(key)); + } + //add timestamp. check for other stuff. + else { + throw new IllegalArgumentException("Unable to load the key \"" + key + + "\", because " + "the type \"" + parameterType + + "\" was not recognized." ); + } + return parameterValue; + } } diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRPolicyFileLoader.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRPolicyFileLoader.java index 17f0aa079..cc97d8580 100644 --- a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRPolicyFileLoader.java +++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/ACRPolicyFileLoader.java @@ -10,90 +10,90 @@ import org.owasp.esapi.errors.AccessControlException; final public class ACRPolicyFileLoader { - protected final Logger logger = ESAPI.getLogger("ACRPolicyFileLoader"); - - public PolicyDTO load() throws AccessControlException { - PolicyDTO policyDTO = new PolicyDTO(); - XMLConfiguration config; - File file = ESAPI.securityConfiguration().getResourceFile("ESAPI-AccessControlPolicy.xml"); - try - { - config = new XMLConfiguration(file); - } - catch(ConfigurationException cex) - { - if(file == null) { - throw new AccessControlException("Unable to load configuration file for the following: " + "ESAPI-AccessControlPolicy.xml", "", cex); - } - throw new AccessControlException("Unable to load configuration file from the following location: " + file.getAbsolutePath(), "", cex); - } + protected final Logger logger = ESAPI.getLogger("ACRPolicyFileLoader"); + + public PolicyDTO load() throws AccessControlException { + PolicyDTO policyDTO = new PolicyDTO(); + XMLConfiguration config; + File file = ESAPI.securityConfiguration().getResourceFile("ESAPI-AccessControlPolicy.xml"); + try + { + config = new XMLConfiguration(file); + } + catch(ConfigurationException cex) + { + if(file == null) { + throw new AccessControlException("Unable to load configuration file for the following: " + "ESAPI-AccessControlPolicy.xml", "", cex); + } + throw new AccessControlException("Unable to load configuration file from the following location: " + file.getAbsolutePath(), "", cex); + } - Object property = config.getProperty("AccessControlRules.AccessControlRule[@name]"); - logger.info(Logger.EVENT_SUCCESS, "Loading Property: " + property); - int numberOfRules = 0; - if(property instanceof Collection) { - numberOfRules = ((Collection)property).size(); - } //implied else property == null -> return new PolicyDTO - - String ruleName = ""; - String ruleClass = ""; - Object rulePolicyParameter = null; - int currentRule = 0; - try { - logger.info(Logger.EVENT_SUCCESS, "Number of rules: " + numberOfRules); - for(currentRule = 0; currentRule < numberOfRules; currentRule++) { - logger.trace(Logger.EVENT_SUCCESS, "----"); - ruleName = config.getString("AccessControlRules.AccessControlRule(" + currentRule + ")[@name]"); - logger.trace(Logger.EVENT_SUCCESS, "Rule name: " + ruleName); - ruleClass = config.getString("AccessControlRules.AccessControlRule(" + currentRule + ")[@class]"); - logger.trace(Logger.EVENT_SUCCESS, "Rule Class: " + ruleClass); - rulePolicyParameter = getPolicyParameter(config, currentRule); - logger.trace(Logger.EVENT_SUCCESS, "rulePolicyParameters: " + rulePolicyParameter); - policyDTO.addAccessControlRule( - ruleName, - ruleClass, - rulePolicyParameter); - } - logger.info(Logger.EVENT_SUCCESS, "policyDTO loaded: " + policyDTO); - } catch (Exception e) { - throw new AccessControlException("Unable to load AccessControlRule parameter. " + - " Rule number: " + currentRule + - " Probably: Rule.name: " + ruleName + - " Probably: Rule.class: " + ruleClass + - e.getMessage(), "", e); - } - return policyDTO; - } + Object property = config.getProperty("AccessControlRules.AccessControlRule[@name]"); + logger.info(Logger.EVENT_SUCCESS, "Loading Property: " + property); + int numberOfRules = 0; + if(property instanceof Collection) { + numberOfRules = ((Collection)property).size(); + } //implied else property == null -> return new PolicyDTO + + String ruleName = ""; + String ruleClass = ""; + Object rulePolicyParameter = null; + int currentRule = 0; + try { + logger.info(Logger.EVENT_SUCCESS, "Number of rules: " + numberOfRules); + for(currentRule = 0; currentRule < numberOfRules; currentRule++) { + logger.trace(Logger.EVENT_SUCCESS, "----"); + ruleName = config.getString("AccessControlRules.AccessControlRule(" + currentRule + ")[@name]"); + logger.trace(Logger.EVENT_SUCCESS, "Rule name: " + ruleName); + ruleClass = config.getString("AccessControlRules.AccessControlRule(" + currentRule + ")[@class]"); + logger.trace(Logger.EVENT_SUCCESS, "Rule Class: " + ruleClass); + rulePolicyParameter = getPolicyParameter(config, currentRule); + logger.trace(Logger.EVENT_SUCCESS, "rulePolicyParameters: " + rulePolicyParameter); + policyDTO.addAccessControlRule( + ruleName, + ruleClass, + rulePolicyParameter); + } + logger.info(Logger.EVENT_SUCCESS, "policyDTO loaded: " + policyDTO); + } catch (Exception e) { + throw new AccessControlException("Unable to load AccessControlRule parameter. " + + " Rule number: " + currentRule + + " Probably: Rule.name: " + ruleName + + " Probably: Rule.class: " + ruleClass + + e.getMessage(), "", e); + } + return policyDTO; + } - protected Object getPolicyParameter(XMLConfiguration config, int currentRule) - throws ClassNotFoundException, IllegalAccessException, InstantiationException, Exception { - //If there aren't any properties: short circuit and return null. -// Properties tempParameters = config.getProperties("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters.Parameter[@name]"); - Object property = config.getProperty("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters.Parameter[@name]"); - if(property == null) { - return null; - } - - int numberOfProperties = 0; - if(property instanceof Collection) { - numberOfProperties = ((Collection)property).size(); - } else { - numberOfProperties = 1; - } - logger.info(Logger.EVENT_SUCCESS, "Number of properties: " + numberOfProperties); - - if(numberOfProperties < 1) { - return null; - } - String parametersLoaderClassName = config.getString("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters[@parametersLoader]"); - if("".equals(parametersLoaderClassName) || parametersLoaderClassName == null) { - //this default should have a properties file override option - parametersLoaderClassName = "org.owasp.esapi.reference.accesscontrol.policyloader.DynaBeanACRParameterLoader"; - } - logger.info(Logger.EVENT_SUCCESS, "Parameters Loader:" + parametersLoaderClassName); - ACRParameterLoader acrParamaterLoader = - (ACRParameterLoader) - Class.forName(parametersLoaderClassName).newInstance(); - return acrParamaterLoader.getParameters(config, currentRule); - } + protected Object getPolicyParameter(XMLConfiguration config, int currentRule) + throws ClassNotFoundException, IllegalAccessException, InstantiationException, Exception { + //If there aren't any properties: short circuit and return null. +// Properties tempParameters = config.getProperties("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters.Parameter[@name]"); + Object property = config.getProperty("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters.Parameter[@name]"); + if(property == null) { + return null; + } + + int numberOfProperties = 0; + if(property instanceof Collection) { + numberOfProperties = ((Collection)property).size(); + } else { + numberOfProperties = 1; + } + logger.info(Logger.EVENT_SUCCESS, "Number of properties: " + numberOfProperties); + + if(numberOfProperties < 1) { + return null; + } + String parametersLoaderClassName = config.getString("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters[@parametersLoader]"); + if("".equals(parametersLoaderClassName) || parametersLoaderClassName == null) { + //this default should have a properties file override option + parametersLoaderClassName = "org.owasp.esapi.reference.accesscontrol.policyloader.DynaBeanACRParameterLoader"; + } + logger.info(Logger.EVENT_SUCCESS, "Parameters Loader:" + parametersLoaderClassName); + ACRParameterLoader acrParamaterLoader = + (ACRParameterLoader) + Class.forName(parametersLoaderClassName).newInstance(); + return acrParamaterLoader.getParameters(config, currentRule); + } } \ No newline at end of file diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/DynaBeanACRParameterLoader.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/DynaBeanACRParameterLoader.java index d57b48872..ce6b28096 100644 --- a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/DynaBeanACRParameterLoader.java +++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/DynaBeanACRParameterLoader.java @@ -8,23 +8,23 @@ import static org.owasp.esapi.reference.accesscontrol.policyloader.ACRParameterLoaderHelper.getParameterValue; final public class DynaBeanACRParameterLoader - implements ACRParameterLoader { - - Logger logger = ESAPI.getLogger(this.getClass()); - -// @Override - public DynaBeanACRParameter getParameters(XMLConfiguration config, int currentRule) throws java.lang.Exception { //TODO reduce the exception - DynaBeanACRParameter policyParameter = new DynaBeanACRParameter(); - int numberOfParameters = config.getList("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters.Parameter[@name]").size(); - for(int currentParameter = 0; currentParameter < numberOfParameters; currentParameter++) { - String parameterName = config.getString("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters.Parameter(" + currentParameter + ")[@name]"); - String parameterType = config.getString("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters.Parameter(" + currentParameter + ")[@type]"); - Object parameterValue = getParameterValue(config, currentRule, currentParameter, parameterType); - policyParameter.set(parameterName, parameterValue); - } - policyParameter.lock(); //This line makes the policyParameter read only. - logger.info(Logger.SECURITY_SUCCESS, "Loaded " + numberOfParameters + - " parameters: " + policyParameter.toString()); - return policyParameter; - } + implements ACRParameterLoader { + + Logger logger = ESAPI.getLogger(this.getClass()); + +// @Override + public DynaBeanACRParameter getParameters(XMLConfiguration config, int currentRule) throws java.lang.Exception { //TODO reduce the exception + DynaBeanACRParameter policyParameter = new DynaBeanACRParameter(); + int numberOfParameters = config.getList("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters.Parameter[@name]").size(); + for(int currentParameter = 0; currentParameter < numberOfParameters; currentParameter++) { + String parameterName = config.getString("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters.Parameter(" + currentParameter + ")[@name]"); + String parameterType = config.getString("AccessControlRules.AccessControlRule(" + currentRule + ").Parameters.Parameter(" + currentParameter + ")[@type]"); + Object parameterValue = getParameterValue(config, currentRule, currentParameter, parameterType); + policyParameter.set(parameterName, parameterValue); + } + policyParameter.lock(); //This line makes the policyParameter read only. + logger.info(Logger.SECURITY_SUCCESS, "Loaded " + numberOfParameters + + " parameters: " + policyParameter.toString()); + return policyParameter; + } } diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/EchoDynaBeanPolicyParameterACR.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/EchoDynaBeanPolicyParameterACR.java index b89aaaef1..4b8424393 100644 --- a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/EchoDynaBeanPolicyParameterACR.java +++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/EchoDynaBeanPolicyParameterACR.java @@ -5,11 +5,11 @@ //public class EchoDynaBeanPolicyParameterACR extends BaseDynaBeanACR { public class EchoDynaBeanPolicyParameterACR extends BaseACR { - /** - * Returns true if runtimeParameter is a Boolean true. - * throws ClassCastException if runtimeParameter is not a Boolean. - */ - public boolean isAuthorized(Object runtimeParameter) throws ClassCastException{ - return getPolicyParameters().getBoolean("isTrue"); - } + /** + * Returns true if runtimeParameter is a Boolean true. + * throws ClassCastException if runtimeParameter is not a Boolean. + */ + public boolean isAuthorized(Object runtimeParameter) throws ClassCastException{ + return getPolicyParameters().getBoolean("isTrue"); + } } \ No newline at end of file diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/PolicyDTO.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/PolicyDTO.java index cfb1e279f..cdf874b9b 100644 --- a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/PolicyDTO.java +++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/PolicyDTO.java @@ -13,43 +13,43 @@ * */ final public class PolicyDTO { - private Map accessControlRules; + private Map accessControlRules; - public PolicyDTO() { - this.accessControlRules = new HashMap(); - } - - public Map getAccessControlRules() { - return accessControlRules; - } + public PolicyDTO() { + this.accessControlRules = new HashMap(); + } + + public Map getAccessControlRules() { + return accessControlRules; + } - public void addAccessControlRule(String key, String accessControlRuleClassName, - Object policyParameter) throws AccessControlException { - if (accessControlRules.get(key) != null) { - throw new AccessControlException("Duplicate keys are not allowed. " - + "Key: " + key, ""); - } - Constructor accessControlRuleConstructor; - try { - - - Class accessControlRuleClass = Class.forName(accessControlRuleClassName, false, this.getClass().getClassLoader()); - accessControlRuleConstructor = accessControlRuleClass - .getConstructor(); - AccessControlRule accessControlRule = - (AccessControlRule) accessControlRuleConstructor - .newInstance(); - accessControlRule.setPolicyParameters(policyParameter); - accessControlRules.put(key, accessControlRule); - } catch (Exception e) { - throw new AccessControlException( - "Unable to create Access Control Rule for key: \"" + key - + "\" with policyParameters: \"" + policyParameter + "\"", - "", - e); - } - } - public String toString() { - return accessControlRules.toString(); - } + public void addAccessControlRule(String key, String accessControlRuleClassName, + Object policyParameter) throws AccessControlException { + if (accessControlRules.get(key) != null) { + throw new AccessControlException("Duplicate keys are not allowed. " + + "Key: " + key, ""); + } + Constructor accessControlRuleConstructor; + try { + + + Class accessControlRuleClass = Class.forName(accessControlRuleClassName, false, this.getClass().getClassLoader()); + accessControlRuleConstructor = accessControlRuleClass + .getConstructor(); + AccessControlRule accessControlRule = + (AccessControlRule) accessControlRuleConstructor + .newInstance(); + accessControlRule.setPolicyParameters(policyParameter); + accessControlRules.put(key, accessControlRule); + } catch (Exception e) { + throw new AccessControlException( + "Unable to create Access Control Rule for key: \"" + key + + "\" with policyParameters: \"" + policyParameter + "\"", + "", + e); + } + } + public String toString() { + return accessControlRules.toString(); + } } diff --git a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/PolicyParameters.java b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/PolicyParameters.java index 9b0d5d48e..8ba44efa6 100644 --- a/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/PolicyParameters.java +++ b/src/main/java/org/owasp/esapi/reference/accesscontrol/policyloader/PolicyParameters.java @@ -2,41 +2,41 @@ public interface PolicyParameters { - /** - * Follows the contract for java.util.Map; - * @param key - * @return The Object referred to by this key, if it exists. - * @see java.util.Map - */ - public abstract Object get(String key); + /** + * Follows the contract for java.util.Map; + * @param key + * @return The Object referred to by this key, if it exists. + * @see java.util.Map + */ + public abstract Object get(String key); - /** - * This works just like a Map, except it will throw an exception if lock() - * has been called. - * @param key - * @param value - * @throws IllegalArgumentException if this DynaBeanACRParameter instance - * has already been locked. - */ - public abstract void set(String key, Object value) - throws IllegalArgumentException; + /** + * This works just like a Map, except it will throw an exception if lock() + * has been called. + * @param key + * @param value + * @throws IllegalArgumentException if this DynaBeanACRParameter instance + * has already been locked. + */ + public abstract void set(String key, Object value) + throws IllegalArgumentException; - /** - * This is a convenience method for developers that prefer to think of this - * as a map instead of being bean-like. - * - * @see #set(String, Object) - */ - public abstract void put(String key, Object value) - throws IllegalArgumentException; + /** + * This is a convenience method for developers that prefer to think of this + * as a map instead of being bean-like. + * + * @see #set(String, Object) + */ + public abstract void put(String key, Object value) + throws IllegalArgumentException; - /** - * This makes the map itself read only, but the mutability of objects - * that this map contains is not affected. Specifically, properties - * cannot be added or removed and the reference cannot be changed to - * a different object, but this does not change whether the values that the - * object contains can be changed. - */ - public abstract void lock(); - + /** + * This makes the map itself read only, but the mutability of objects + * that this map contains is not affected. Specifically, properties + * cannot be added or removed and the reference cannot be changed to + * a different object, but this does not change whether the values that the + * object contains can be changed. + */ + public abstract void lock(); + } \ No newline at end of file diff --git a/src/main/java/org/owasp/esapi/reference/crypto/DefaultEncryptedProperties.java b/src/main/java/org/owasp/esapi/reference/crypto/DefaultEncryptedProperties.java index af7b524dc..c5ee8ad0f 100644 --- a/src/main/java/org/owasp/esapi/reference/crypto/DefaultEncryptedProperties.java +++ b/src/main/java/org/owasp/esapi/reference/crypto/DefaultEncryptedProperties.java @@ -53,164 +53,164 @@ */ public class DefaultEncryptedProperties implements org.owasp.esapi.EncryptedProperties { - /** The properties. */ - private final Properties properties = new Properties(); - - /** The logger. */ - private final Logger logger = ESAPI.getLogger("EncryptedProperties"); - - /** - * Instantiates a new encrypted properties. - */ - public DefaultEncryptedProperties() { - // hidden - } - - /** - * {@inheritDoc} - */ - public synchronized String getProperty(String key) throws EncryptionException { - String[] errorMsgs = new String[] { - ": failed decoding from base64", - ": failed to deserialize properly", - ": failed to decrypt properly" - }; - - int progressMark = 0; - try { - String encryptedValue = properties.getProperty(key); - - if(encryptedValue==null) - return null; - - progressMark = 0; - byte[] serializedCiphertext = ESAPI.encoder().decodeFromBase64(encryptedValue); - progressMark++; - CipherText restoredCipherText = CipherText.fromPortableSerializedBytes(serializedCiphertext); - progressMark++; - PlainText plaintext = ESAPI.encryptor().decrypt(restoredCipherText); - - return plaintext.toString(); - } catch (Exception e) { - throw new EncryptionException("Property retrieval failure", - "Couldn't retrieve encrypted property for property " + key + - errorMsgs[progressMark], e); - } - } - - /** - * {@inheritDoc} - */ - public synchronized String setProperty(String key, String value) throws EncryptionException { - String[] errorMsgs = new String[] { - ": failed to encrypt properly", - ": failed to serialize correctly", - ": failed to base64-encode properly", - ": failed to set base64-encoded value as property. Illegal key name?" - }; - - int progressMark = 0; - try { - if ( key == null ) { - throw new NullPointerException("Property name may not be null."); - } - if ( value == null ) { - throw new NullPointerException("Property value may not be null."); - } - // NOTE: Not backward compatible w/ ESAPI 1.4. - PlainText pt = new PlainText(value); - CipherText ct = ESAPI.encryptor().encrypt(pt); - progressMark++; - byte[] serializedCiphertext = ct.asPortableSerializedByteArray(); - progressMark++; - String b64str = ESAPI.encoder().encodeForBase64(serializedCiphertext, false); - progressMark++; - String encryptedValue = (String)properties.setProperty(key, b64str); - progressMark++; - return encryptedValue; - } catch (Exception e) { - throw new EncryptionException("Property setting failure", - "Couldn't set encrypted property " + key + - errorMsgs[progressMark], e); - } - } - - /** - * {@inheritDoc} - */ - public Set keySet() { - return properties.keySet(); - } - - /** - * {@inheritDoc} - */ - public void load(InputStream in) throws IOException { - properties.load(in); - logger.trace(Logger.SECURITY_SUCCESS, "Encrypted properties loaded successfully"); - } - - /** - * {@inheritDoc} - */ - public void store(OutputStream out, String comments) throws IOException { - properties.store(out, comments); - } - - /** - * Loads encrypted properties file based on the location passed in args then prompts the - * user to input key-value pairs. When the user enters a null or blank key, the values - * are stored to the properties file. - * - * @param args - * the location of the properties file to load and write to - * - * @throws Exception - * Any exception thrown - * @deprecated Use {@code EncryptedPropertiesUtils} instead, which allows creating, reading, - * and writing encrypted properties. {@code main} method will be removed in a - * future release. - */ + /** The properties. */ + private final Properties properties = new Properties(); + + /** The logger. */ + private final Logger logger = ESAPI.getLogger("EncryptedProperties"); + + /** + * Instantiates a new encrypted properties. + */ + public DefaultEncryptedProperties() { + // hidden + } + + /** + * {@inheritDoc} + */ + public synchronized String getProperty(String key) throws EncryptionException { + String[] errorMsgs = new String[] { + ": failed decoding from base64", + ": failed to deserialize properly", + ": failed to decrypt properly" + }; + + int progressMark = 0; + try { + String encryptedValue = properties.getProperty(key); + + if(encryptedValue==null) + return null; + + progressMark = 0; + byte[] serializedCiphertext = ESAPI.encoder().decodeFromBase64(encryptedValue); + progressMark++; + CipherText restoredCipherText = CipherText.fromPortableSerializedBytes(serializedCiphertext); + progressMark++; + PlainText plaintext = ESAPI.encryptor().decrypt(restoredCipherText); + + return plaintext.toString(); + } catch (Exception e) { + throw new EncryptionException("Property retrieval failure", + "Couldn't retrieve encrypted property for property " + key + + errorMsgs[progressMark], e); + } + } + + /** + * {@inheritDoc} + */ + public synchronized String setProperty(String key, String value) throws EncryptionException { + String[] errorMsgs = new String[] { + ": failed to encrypt properly", + ": failed to serialize correctly", + ": failed to base64-encode properly", + ": failed to set base64-encoded value as property. Illegal key name?" + }; + + int progressMark = 0; + try { + if ( key == null ) { + throw new NullPointerException("Property name may not be null."); + } + if ( value == null ) { + throw new NullPointerException("Property value may not be null."); + } + // NOTE: Not backward compatible w/ ESAPI 1.4. + PlainText pt = new PlainText(value); + CipherText ct = ESAPI.encryptor().encrypt(pt); + progressMark++; + byte[] serializedCiphertext = ct.asPortableSerializedByteArray(); + progressMark++; + String b64str = ESAPI.encoder().encodeForBase64(serializedCiphertext, false); + progressMark++; + String encryptedValue = (String)properties.setProperty(key, b64str); + progressMark++; + return encryptedValue; + } catch (Exception e) { + throw new EncryptionException("Property setting failure", + "Couldn't set encrypted property " + key + + errorMsgs[progressMark], e); + } + } + + /** + * {@inheritDoc} + */ + public Set keySet() { + return properties.keySet(); + } + + /** + * {@inheritDoc} + */ + public void load(InputStream in) throws IOException { + properties.load(in); + logger.trace(Logger.SECURITY_SUCCESS, "Encrypted properties loaded successfully"); + } + + /** + * {@inheritDoc} + */ + public void store(OutputStream out, String comments) throws IOException { + properties.store(out, comments); + } + + /** + * Loads encrypted properties file based on the location passed in args then prompts the + * user to input key-value pairs. When the user enters a null or blank key, the values + * are stored to the properties file. + * + * @param args + * the location of the properties file to load and write to + * + * @throws Exception + * Any exception thrown + * @deprecated Use {@code EncryptedPropertiesUtils} instead, which allows creating, reading, + * and writing encrypted properties. {@code main} method will be removed in a + * future release. + */ @Deprecated - public static void main(String[] args) throws Exception { - File f = new File(args[0]); - ESAPI.getLogger( "EncryptedProperties.main" ).debug(Logger.SECURITY_SUCCESS, "Loading encrypted properties from " + f.getAbsolutePath() ); - if ( !f.exists() ) throw new IOException( "Properties file not found: " + f.getAbsolutePath() ); - ESAPI.getLogger( "EncryptedProperties.main" ).debug(Logger.SECURITY_SUCCESS, "Encrypted properties found in " + f.getAbsolutePath() ); - DefaultEncryptedProperties ep = new DefaultEncryptedProperties(); - - FileInputStream in = null; - FileOutputStream out = null; - try { - in = new FileInputStream(f); + public static void main(String[] args) throws Exception { + File f = new File(args[0]); + ESAPI.getLogger( "EncryptedProperties.main" ).debug(Logger.SECURITY_SUCCESS, "Loading encrypted properties from " + f.getAbsolutePath() ); + if ( !f.exists() ) throw new IOException( "Properties file not found: " + f.getAbsolutePath() ); + ESAPI.getLogger( "EncryptedProperties.main" ).debug(Logger.SECURITY_SUCCESS, "Encrypted properties found in " + f.getAbsolutePath() ); + DefaultEncryptedProperties ep = new DefaultEncryptedProperties(); + + FileInputStream in = null; + FileOutputStream out = null; + try { + in = new FileInputStream(f); out = new FileOutputStream(f); ep.load(in); - BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); - String key = null; - do { - System.out.print("Enter key: "); - key = br.readLine(); - System.out.print("Enter value: "); - String value = br.readLine(); - if (key != null && key.length() > 0 && value != null && value.length() > 0) { - ep.setProperty(key, value); - } - } while (key != null && key.length() > 0); - ep.store(out, "Encrypted Properties File"); - } finally { - // FindBugs and PMD both complain about these next lines, that they may - // ignore thrown exceptions. Really!!! That's the whole point. - try { if ( in != null ) in.close(); } catch( Exception e ) {} - try { if ( out != null ) out.close(); } catch( Exception e ) {} - } - - Iterator i = ep.keySet().iterator(); - while (i.hasNext()) { - String k = (String) i.next(); - String value = ep.getProperty(k); - System.out.println(" " + k + "=" + value); - } - } + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + String key = null; + do { + System.out.print("Enter key: "); + key = br.readLine(); + System.out.print("Enter value: "); + String value = br.readLine(); + if (key != null && key.length() > 0 && value != null && value.length() > 0) { + ep.setProperty(key, value); + } + } while (key != null && key.length() > 0); + ep.store(out, "Encrypted Properties File"); + } finally { + // FindBugs and PMD both complain about these next lines, that they may + // ignore thrown exceptions. Really!!! That's the whole point. + try { if ( in != null ) in.close(); } catch( Exception e ) {} + try { if ( out != null ) out.close(); } catch( Exception e ) {} + } + + Iterator i = ep.keySet().iterator(); + while (i.hasNext()) { + String k = (String) i.next(); + String value = ep.getProperty(k); + System.out.println(" " + k + "=" + value); + } + } } diff --git a/src/main/java/org/owasp/esapi/reference/crypto/EncryptedPropertiesUtils.java b/src/main/java/org/owasp/esapi/reference/crypto/EncryptedPropertiesUtils.java index cb1d512d0..6aa93aa50 100644 --- a/src/main/java/org/owasp/esapi/reference/crypto/EncryptedPropertiesUtils.java +++ b/src/main/java/org/owasp/esapi/reference/crypto/EncryptedPropertiesUtils.java @@ -18,7 +18,7 @@ * Usage:
    * * java org.owasp.esapi.reference.crypto.EncryptedPropertiesUtils [--in file] [--out file] - * [--in-encrypted true|false] [--verbose true|false] + * [--in-encrypted true|false] [--verbose true|false] * *

    * Command line parameters:
    @@ -36,177 +36,177 @@ */ public class EncryptedPropertiesUtils { - /** - * Loads encrypted or plaintext properties file based on the location passed in args - * then prompts the user to input key-value pairs. When the user enters a null or - * blank key, the values are stored to the properties file. - * - * @throws Exception Any exception thrown - */ - public static void main(String[] args) throws Exception { - - //command line options - String inFile = null; - String outFile = null; - boolean inFileEncrypted = true; - boolean verbose = false; - - //parse command line params - for (int i = 0; i < args.length; i = i + 2) { - String paramType = args[i]; - - if ("--in".equals(paramType) && args.length >= i + 1) { - inFile = args[i + 1]; - - } else if ("--out".equals(paramType) && args.length >= i + 1) { - outFile = args[i + 1]; - - } else if ("--in-encrypted".equals(paramType) && args.length >= i + 1) { - inFileEncrypted = Boolean.valueOf(args[i + 1]); - - } else if ("--verbose".equals(paramType) && args.length >= i + 1) { - verbose = Boolean.valueOf(args[i + 1]); - } - - } - - if (outFile == null) { - outFile = inFile; //if no output file is specified we will overwrite the input file - } - if (outFile == null) { - //no input or output file specified. Can't continue. - System.out.println("You must specify an input file or output file"); - System.exit(1); - } - - //load in existing properties from a file - Properties props = loadProperties(inFile, inFileEncrypted); - - //read user input and add keys and values to the property file - BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); - String key = null; - do { - System.out.print("Enter key: "); - key = br.readLine(); - - if (props.containsKey(key)) { - System.out.print("Key already exists. Replace? "); - String confirm = br.readLine(); - if (!("y".equals(confirm) || "yes".equals(confirm))) { - continue; - } - } - - System.out.print("Enter value: "); - String value = br.readLine(); - - addProperty(props, key, value); - - } while (key != null && key.length() > 0); - - //save output file - storeProperties(outFile, props, - "Encrypted Properties File generated by org.owasp.esapi.reference.crypto.EncryptedPropertiesUtils"); - - System.out.println("Encrypted Properties file output to " + outFile); - - if (verbose) { - for (Object oKey : props.keySet()) { - String sKey = (String) oKey; - String value = props.getProperty(sKey); - System.out.println(" " + sKey + "=" + value); - } - } - - } - - /** - * Loads a Properties file from a filename. If the filename is unspecified - * or the file could not be found, a new Properties is returned. - * - * @param inFile Filename to load Properties from. - * @param inFileEncrypted If true, the input file is assumed to be already encrypted. Default true. - * @return Either the loaded Properties object or a new one if the file could not be found. - * @throws IOException - */ - public static Properties loadProperties(String inFile, Boolean inFileEncrypted) throws IOException { - - if (inFileEncrypted == null) inFileEncrypted = true; - - Properties props; - - if (inFile != null) { - - File f = new File(inFile); - if (!f.exists()) { - System.out.println("Input properties file not found. Creating new."); - props = new ReferenceEncryptedProperties(); - - } else { - String encrypted = inFileEncrypted ? "Encrypted" : "Plaintext"; - System.out.println(encrypted + " properties found in " + f.getAbsolutePath()); - - Properties inProperties; - if (inFileEncrypted) { - inProperties = new ReferenceEncryptedProperties(); - } else { - inProperties = new Properties(); - } - - InputStream in = null; - try { - in = new FileInputStream(f); - inProperties.load(in); - } finally { - try { - if (in != null) in.close(); //quietly close the InputStream - } catch (Exception e) {} - } - - //Use the existing properties - props = new ReferenceEncryptedProperties(inProperties); - } - } else { - System.out.println("Input properties file not found. Creating new."); - props = new ReferenceEncryptedProperties(); - } - - return props; - } - - /** - * Stores a Properties object to a file. - * - * @param outFile Filename to store to - * @param props Properties to store - * @param message A message to add to the comments in the stored file - * @throws Exception - */ - public static void storeProperties(String outFile, Properties props, String message) throws Exception { - OutputStream out = null; - try { - out = new FileOutputStream(new File(outFile)); - props.store(out, message); - } finally { - try { - if (out != null) out.close(); //quietly close OutputStream - } catch (Exception e) {} - } - } - - /** - * Adds a new key-value property to the passed Properties object - * - * @param props The Properties object to add to - * @param key The key to add - * @param value The value to set - * @return The previous value of the property, or null if it is newly added. - */ - public static Object addProperty(Properties props, String key, String value) { - if (props != null && key != null && key.length() > 0 && value != null && value.length() > 0) { - return props.setProperty(key, value); - } - return null; - } - + /** + * Loads encrypted or plaintext properties file based on the location passed in args + * then prompts the user to input key-value pairs. When the user enters a null or + * blank key, the values are stored to the properties file. + * + * @throws Exception Any exception thrown + */ + public static void main(String[] args) throws Exception { + + //command line options + String inFile = null; + String outFile = null; + boolean inFileEncrypted = true; + boolean verbose = false; + + //parse command line params + for (int i = 0; i < args.length; i = i + 2) { + String paramType = args[i]; + + if ("--in".equals(paramType) && args.length >= i + 1) { + inFile = args[i + 1]; + + } else if ("--out".equals(paramType) && args.length >= i + 1) { + outFile = args[i + 1]; + + } else if ("--in-encrypted".equals(paramType) && args.length >= i + 1) { + inFileEncrypted = Boolean.valueOf(args[i + 1]); + + } else if ("--verbose".equals(paramType) && args.length >= i + 1) { + verbose = Boolean.valueOf(args[i + 1]); + } + + } + + if (outFile == null) { + outFile = inFile; //if no output file is specified we will overwrite the input file + } + if (outFile == null) { + //no input or output file specified. Can't continue. + System.out.println("You must specify an input file or output file"); + System.exit(1); + } + + //load in existing properties from a file + Properties props = loadProperties(inFile, inFileEncrypted); + + //read user input and add keys and values to the property file + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + String key = null; + do { + System.out.print("Enter key: "); + key = br.readLine(); + + if (props.containsKey(key)) { + System.out.print("Key already exists. Replace? "); + String confirm = br.readLine(); + if (!("y".equals(confirm) || "yes".equals(confirm))) { + continue; + } + } + + System.out.print("Enter value: "); + String value = br.readLine(); + + addProperty(props, key, value); + + } while (key != null && key.length() > 0); + + //save output file + storeProperties(outFile, props, + "Encrypted Properties File generated by org.owasp.esapi.reference.crypto.EncryptedPropertiesUtils"); + + System.out.println("Encrypted Properties file output to " + outFile); + + if (verbose) { + for (Object oKey : props.keySet()) { + String sKey = (String) oKey; + String value = props.getProperty(sKey); + System.out.println(" " + sKey + "=" + value); + } + } + + } + + /** + * Loads a Properties file from a filename. If the filename is unspecified + * or the file could not be found, a new Properties is returned. + * + * @param inFile Filename to load Properties from. + * @param inFileEncrypted If true, the input file is assumed to be already encrypted. Default true. + * @return Either the loaded Properties object or a new one if the file could not be found. + * @throws IOException + */ + public static Properties loadProperties(String inFile, Boolean inFileEncrypted) throws IOException { + + if (inFileEncrypted == null) inFileEncrypted = true; + + Properties props; + + if (inFile != null) { + + File f = new File(inFile); + if (!f.exists()) { + System.out.println("Input properties file not found. Creating new."); + props = new ReferenceEncryptedProperties(); + + } else { + String encrypted = inFileEncrypted ? "Encrypted" : "Plaintext"; + System.out.println(encrypted + " properties found in " + f.getAbsolutePath()); + + Properties inProperties; + if (inFileEncrypted) { + inProperties = new ReferenceEncryptedProperties(); + } else { + inProperties = new Properties(); + } + + InputStream in = null; + try { + in = new FileInputStream(f); + inProperties.load(in); + } finally { + try { + if (in != null) in.close(); //quietly close the InputStream + } catch (Exception e) {} + } + + //Use the existing properties + props = new ReferenceEncryptedProperties(inProperties); + } + } else { + System.out.println("Input properties file not found. Creating new."); + props = new ReferenceEncryptedProperties(); + } + + return props; + } + + /** + * Stores a Properties object to a file. + * + * @param outFile Filename to store to + * @param props Properties to store + * @param message A message to add to the comments in the stored file + * @throws Exception + */ + public static void storeProperties(String outFile, Properties props, String message) throws Exception { + OutputStream out = null; + try { + out = new FileOutputStream(new File(outFile)); + props.store(out, message); + } finally { + try { + if (out != null) out.close(); //quietly close OutputStream + } catch (Exception e) {} + } + } + + /** + * Adds a new key-value property to the passed Properties object + * + * @param props The Properties object to add to + * @param key The key to add + * @param value The value to set + * @return The previous value of the property, or null if it is newly added. + */ + public static Object addProperty(Properties props, String key, String value) { + if (props != null && key != null && key.length() > 0 && value != null && value.length() > 0) { + return props.setProperty(key, value); + } + return null; + } + } diff --git a/src/main/java/org/owasp/esapi/reference/crypto/ReferenceEncryptedProperties.java b/src/main/java/org/owasp/esapi/reference/crypto/ReferenceEncryptedProperties.java index 0d35b25dd..d5a375449 100644 --- a/src/main/java/org/owasp/esapi/reference/crypto/ReferenceEncryptedProperties.java +++ b/src/main/java/org/owasp/esapi/reference/crypto/ReferenceEncryptedProperties.java @@ -55,239 +55,239 @@ */ public class ReferenceEncryptedProperties extends java.util.Properties implements EncryptedProperties { - /** - * serverVersionUID; use format of YYYYMMDD. - */ - private static final long serialVersionUID = 20120718L; - - /** The logger. */ - private final Logger logger = ESAPI.getLogger(this.getClass()); - - private static final String[] GET_ERROR_MESSAGES = new String[]{ - ": failed decoding from base64", - ": failed to deserialize properly", - ": failed to decrypt properly" - }; - - private static final String[] SET_ERROR_MESSAGES = new String[]{ - ": failed to encrypt properly", - ": failed to serialize correctly", - ": failed to base64-encode properly", - ": failed to set base64-encoded value as property. Illegal key name?" - }; - - /** - * Instantiates a new encrypted properties. - */ - public ReferenceEncryptedProperties() { - super(); - } - - public ReferenceEncryptedProperties(Properties defaults) { - super(); - - for (Object oKey : defaults.keySet()) { - String key = (oKey instanceof String) ? (String)oKey : oKey.toString(); - String value = defaults.getProperty(key); - - this.setProperty(key, value); - } - } - - /** - * {@inheritDoc} - * - * @throws EncryptionRuntimeException Thrown if decryption fails. - */ - @Override - public synchronized String getProperty(String key) throws EncryptionRuntimeException { - int progressMark = 0; - try { - String encryptedValue = super.getProperty(key); - - if(encryptedValue==null) - return null; - - progressMark = 0; - byte[] serializedCiphertext = ESAPI.encoder().decodeFromBase64(encryptedValue); - progressMark++; - CipherText restoredCipherText = CipherText.fromPortableSerializedBytes(serializedCiphertext); - progressMark++; - PlainText plaintext = ESAPI.encryptor().decrypt(restoredCipherText); - - return plaintext.toString(); - } catch (Exception e) { - throw new EncryptionRuntimeException("Property retrieval failure", - "Couldn't retrieve encrypted property for property " + key + - GET_ERROR_MESSAGES[progressMark], e); - } - } - - /** - * {@inheritDoc} - * - * @throws EncryptionRuntimeException Thrown if decryption fails. - */ - @Override - public synchronized String getProperty(String key, String defaultValue) throws EncryptionRuntimeException { - String value = getProperty(key); - - if (value == null) return defaultValue; - - return value; - } - - /** - * {@inheritDoc} - * - * @throws EncryptionRuntimeException Thrown if encryption fails. - */ - @Override - public synchronized String setProperty(String key, String value) throws EncryptionRuntimeException { - int progressMark = 0; - try { - if ( key == null ) { - throw new NullPointerException("Property name may not be null."); - } - if ( value == null ) { - throw new NullPointerException("Property value may not be null."); - } - // NOTE: Not backward compatible w/ ESAPI 1.4. - PlainText pt = new PlainText(value); - CipherText ct = ESAPI.encryptor().encrypt(pt); - progressMark++; - byte[] serializedCiphertext = ct.asPortableSerializedByteArray(); - progressMark++; - String b64str = ESAPI.encoder().encodeForBase64(serializedCiphertext, false); - progressMark++; - return (String)super.put(key, b64str); - } catch (Exception e) { - throw new EncryptionRuntimeException("Property setting failure", - "Couldn't set encrypted property " + key + - SET_ERROR_MESSAGES[progressMark], e); - } - } - - /** - * {@inheritDoc} - * @throws IOException Thrown if input stream invalid or does not - * correspond to Java properties file format. - */ - @Override - public void load(InputStream in) throws IOException { - super.load(in); - logger.trace(Logger.SECURITY_SUCCESS, "Encrypted properties loaded successfully"); - } - - /** - * {@inheritDoc} - * - * For JDK 1.5 compatibility, this method has been overridden convert the Reader - * into an InputStream and call the superclass constructor. - * - * @throws IOException Thrown if {@code Reader} input stream invalid or does not - * correspond to Java properties file format. - */ - public void load(Reader in) throws IOException { - - if (in == null) return; - - //read from the reader into a StringBuffer - char[] cbuf = new char[65536]; - BufferedReader buff = new BufferedReader(in); - StringBuilder contents = new StringBuilder(); - - int read_this_time = 0; - while (read_this_time != -1) { - read_this_time = buff.read(cbuf, 0, 65536); - if (read_this_time > 0) contents.append(cbuf, 0, read_this_time); - } - - //create a new InputStream from the StringBuffer - InputStream is = new ByteArrayInputStream(contents.toString().getBytes()); - - super.load(is); - logger.trace(Logger.SECURITY_SUCCESS, "Encrypted properties loaded successfully"); - } - - /** - * This method has been overridden to throw an {@code UnsupportedOperationException} - */ - @Override - public void list(PrintStream out) { - throw new UnsupportedOperationException("This method has been removed for security."); - } - - /** - * This method has been overridden to throw an {@code UnsupportedOperationException} - */ - @Override - public void list(PrintWriter out) { - throw new UnsupportedOperationException("This method has been removed for security."); - } - - /** - * This method has been overridden to throw an {@code UnsupportedOperationException} - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Override - public Collection values() { - throw new UnsupportedOperationException("This method has been removed for security."); - } - - /** - * This method has been overridden to throw an {@code UnsupportedOperationException} - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Override - public Set entrySet() { - throw new UnsupportedOperationException("This method has been removed for security."); - } - - /** - * This method has been overridden to throw an {@code UnsupportedOperationException} - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Override - public Enumeration elements() { - throw new UnsupportedOperationException("This method has been removed for security."); - } - - /** - * This method has been overridden to only accept Strings for key and value, and to encrypt - * those Strings before storing them. Outside classes should always use {@code setProperty} - * to add values to the Properties map. If an outside class does erroneously call this method - * with non-String parameters an {@code IllegalArgumentException} will be thrown. - * - * @param key A String key to add - * @param value A String value to add - * @return The old value associated with the specified key, or {@code null} - * if the key did not exist. - */ - @Override - public synchronized Object put(Object key, Object value) { - //if java.util.Properties is calling this method, just forward to the implementation in - //the superclass (java.util.Hashtable) - Throwable t = new Throwable(); - for (StackTraceElement trace : t.getStackTrace()) { - if ("java.util.Properties".equals(trace.getClassName()) ) return super.put(key, value); - } - - //otherwise, if both arguments are Strings, encrypt and store them - if (key instanceof String && value instanceof String) return setProperty((String)key, (String)value); - - //other Object types are not allowed - throw new IllegalArgumentException("This method has been overridden to only accept Strings for key and value."); - } - - /** - * This method has been overridden to not print out the keys and values stored in this properties file. - * - * @return The minimal String representation of this class, as per java.lang.Object. - */ - @Override - public String toString() { - return getClass().getName() + "@" + Integer.toHexString(hashCode()); - } + /** + * serverVersionUID; use format of YYYYMMDD. + */ + private static final long serialVersionUID = 20120718L; + + /** The logger. */ + private final Logger logger = ESAPI.getLogger(this.getClass()); + + private static final String[] GET_ERROR_MESSAGES = new String[]{ + ": failed decoding from base64", + ": failed to deserialize properly", + ": failed to decrypt properly" + }; + + private static final String[] SET_ERROR_MESSAGES = new String[]{ + ": failed to encrypt properly", + ": failed to serialize correctly", + ": failed to base64-encode properly", + ": failed to set base64-encoded value as property. Illegal key name?" + }; + + /** + * Instantiates a new encrypted properties. + */ + public ReferenceEncryptedProperties() { + super(); + } + + public ReferenceEncryptedProperties(Properties defaults) { + super(); + + for (Object oKey : defaults.keySet()) { + String key = (oKey instanceof String) ? (String)oKey : oKey.toString(); + String value = defaults.getProperty(key); + + this.setProperty(key, value); + } + } + + /** + * {@inheritDoc} + * + * @throws EncryptionRuntimeException Thrown if decryption fails. + */ + @Override + public synchronized String getProperty(String key) throws EncryptionRuntimeException { + int progressMark = 0; + try { + String encryptedValue = super.getProperty(key); + + if(encryptedValue==null) + return null; + + progressMark = 0; + byte[] serializedCiphertext = ESAPI.encoder().decodeFromBase64(encryptedValue); + progressMark++; + CipherText restoredCipherText = CipherText.fromPortableSerializedBytes(serializedCiphertext); + progressMark++; + PlainText plaintext = ESAPI.encryptor().decrypt(restoredCipherText); + + return plaintext.toString(); + } catch (Exception e) { + throw new EncryptionRuntimeException("Property retrieval failure", + "Couldn't retrieve encrypted property for property " + key + + GET_ERROR_MESSAGES[progressMark], e); + } + } + + /** + * {@inheritDoc} + * + * @throws EncryptionRuntimeException Thrown if decryption fails. + */ + @Override + public synchronized String getProperty(String key, String defaultValue) throws EncryptionRuntimeException { + String value = getProperty(key); + + if (value == null) return defaultValue; + + return value; + } + + /** + * {@inheritDoc} + * + * @throws EncryptionRuntimeException Thrown if encryption fails. + */ + @Override + public synchronized String setProperty(String key, String value) throws EncryptionRuntimeException { + int progressMark = 0; + try { + if ( key == null ) { + throw new NullPointerException("Property name may not be null."); + } + if ( value == null ) { + throw new NullPointerException("Property value may not be null."); + } + // NOTE: Not backward compatible w/ ESAPI 1.4. + PlainText pt = new PlainText(value); + CipherText ct = ESAPI.encryptor().encrypt(pt); + progressMark++; + byte[] serializedCiphertext = ct.asPortableSerializedByteArray(); + progressMark++; + String b64str = ESAPI.encoder().encodeForBase64(serializedCiphertext, false); + progressMark++; + return (String)super.put(key, b64str); + } catch (Exception e) { + throw new EncryptionRuntimeException("Property setting failure", + "Couldn't set encrypted property " + key + + SET_ERROR_MESSAGES[progressMark], e); + } + } + + /** + * {@inheritDoc} + * @throws IOException Thrown if input stream invalid or does not + * correspond to Java properties file format. + */ + @Override + public void load(InputStream in) throws IOException { + super.load(in); + logger.trace(Logger.SECURITY_SUCCESS, "Encrypted properties loaded successfully"); + } + + /** + * {@inheritDoc} + * + * For JDK 1.5 compatibility, this method has been overridden convert the Reader + * into an InputStream and call the superclass constructor. + * + * @throws IOException Thrown if {@code Reader} input stream invalid or does not + * correspond to Java properties file format. + */ + public void load(Reader in) throws IOException { + + if (in == null) return; + + //read from the reader into a StringBuffer + char[] cbuf = new char[65536]; + BufferedReader buff = new BufferedReader(in); + StringBuilder contents = new StringBuilder(); + + int read_this_time = 0; + while (read_this_time != -1) { + read_this_time = buff.read(cbuf, 0, 65536); + if (read_this_time > 0) contents.append(cbuf, 0, read_this_time); + } + + //create a new InputStream from the StringBuffer + InputStream is = new ByteArrayInputStream(contents.toString().getBytes()); + + super.load(is); + logger.trace(Logger.SECURITY_SUCCESS, "Encrypted properties loaded successfully"); + } + + /** + * This method has been overridden to throw an {@code UnsupportedOperationException} + */ + @Override + public void list(PrintStream out) { + throw new UnsupportedOperationException("This method has been removed for security."); + } + + /** + * This method has been overridden to throw an {@code UnsupportedOperationException} + */ + @Override + public void list(PrintWriter out) { + throw new UnsupportedOperationException("This method has been removed for security."); + } + + /** + * This method has been overridden to throw an {@code UnsupportedOperationException} + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public Collection values() { + throw new UnsupportedOperationException("This method has been removed for security."); + } + + /** + * This method has been overridden to throw an {@code UnsupportedOperationException} + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public Set entrySet() { + throw new UnsupportedOperationException("This method has been removed for security."); + } + + /** + * This method has been overridden to throw an {@code UnsupportedOperationException} + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public Enumeration elements() { + throw new UnsupportedOperationException("This method has been removed for security."); + } + + /** + * This method has been overridden to only accept Strings for key and value, and to encrypt + * those Strings before storing them. Outside classes should always use {@code setProperty} + * to add values to the Properties map. If an outside class does erroneously call this method + * with non-String parameters an {@code IllegalArgumentException} will be thrown. + * + * @param key A String key to add + * @param value A String value to add + * @return The old value associated with the specified key, or {@code null} + * if the key did not exist. + */ + @Override + public synchronized Object put(Object key, Object value) { + //if java.util.Properties is calling this method, just forward to the implementation in + //the superclass (java.util.Hashtable) + Throwable t = new Throwable(); + for (StackTraceElement trace : t.getStackTrace()) { + if ("java.util.Properties".equals(trace.getClassName()) ) return super.put(key, value); + } + + //otherwise, if both arguments are Strings, encrypt and store them + if (key instanceof String && value instanceof String) return setProperty((String)key, (String)value); + + //other Object types are not allowed + throw new IllegalArgumentException("This method has been overridden to only accept Strings for key and value."); + } + + /** + * This method has been overridden to not print out the keys and values stored in this properties file. + * + * @return The minimal String representation of this class, as per java.lang.Object. + */ + @Override + public String toString() { + return getClass().getName() + "@" + Integer.toHexString(hashCode()); + } } diff --git a/src/main/java/org/owasp/esapi/reference/validation/BaseValidationRule.java b/src/main/java/org/owasp/esapi/reference/validation/BaseValidationRule.java index 031a35467..275ca2725 100644 --- a/src/main/java/org/owasp/esapi/reference/validation/BaseValidationRule.java +++ b/src/main/java/org/owasp/esapi/reference/validation/BaseValidationRule.java @@ -37,166 +37,166 @@ */ public abstract class BaseValidationRule implements ValidationRule { - private String typeName = null; - protected boolean allowNull = false; - protected Encoder encoder = null; - - private BaseValidationRule() { - // prevent use of no-arg constructor - } - - public BaseValidationRule( String typeName ) { - this(); - setEncoder( ESAPI.encoder() ); - setTypeName( typeName ); - } - - public BaseValidationRule( String typeName, Encoder encoder ) { - this(); - setEncoder( encoder ); - setTypeName( typeName ); - } - + private String typeName = null; + protected boolean allowNull = false; + protected Encoder encoder = null; + + private BaseValidationRule() { + // prevent use of no-arg constructor + } + + public BaseValidationRule( String typeName ) { + this(); + setEncoder( ESAPI.encoder() ); + setTypeName( typeName ); + } + + public BaseValidationRule( String typeName, Encoder encoder ) { + this(); + setEncoder( encoder ); + setTypeName( typeName ); + } + /** * {@inheritDoc} - */ - public void setAllowNull( boolean flag ) { - allowNull = flag; - } + */ + public void setAllowNull( boolean flag ) { + allowNull = flag; + } /** * {@inheritDoc} - */ - public String getTypeName() { - return typeName; - } - + */ + public String getTypeName() { + return typeName; + } + /** * {@inheritDoc} - */ - public final void setTypeName( String typeName ) { - this.typeName = typeName; - } - + */ + public final void setTypeName( String typeName ) { + this.typeName = typeName; + } + /** * {@inheritDoc} - */ - public final void setEncoder( Encoder encoder ) { - this.encoder = encoder; - } - + */ + public final void setEncoder( Encoder encoder ) { + this.encoder = encoder; + } + /** * {@inheritDoc} - */ - public void assertValid( String context, String input ) throws ValidationException { - getValid( context, input ); - } + */ + public void assertValid( String context, String input ) throws ValidationException { + getValid( context, input ); + } /** * {@inheritDoc} - */ - public Object getValid( String context, String input, ValidationErrorList errorList ) throws ValidationException { - Object valid = null; - try { - valid = getValid( context, input ); - } catch (ValidationException e) { - if( errorList == null) { - throw e; - } else { - errorList.addError(context, e); - } - } - return valid; - } - + */ + public Object getValid( String context, String input, ValidationErrorList errorList ) throws ValidationException { + Object valid = null; + try { + valid = getValid( context, input ); + } catch (ValidationException e) { + if( errorList == null) { + throw e; + } else { + errorList.addError(context, e); + } + } + return valid; + } + /** * {@inheritDoc} - */ - public Object getSafe( String context, String input ) { - Object valid = null; - try { - valid = getValid( context, input ); - } catch ( ValidationException e ) { - return sanitize( context, input ); - } - return valid; - } + */ + public Object getSafe( String context, String input ) { + Object valid = null; + try { + valid = getValid( context, input ); + } catch ( ValidationException e ) { + return sanitize( context, input ); + } + return valid; + } - /** - * The method is similar to ValidationRuile.getSafe except that it returns a - * harmless object that may or may not have any similarity to the original - * input (in some cases you may not care). In most cases this should be the - * same as the getSafe method only instead of throwing an exception, return - * some default value. - * - * @param context - * @param input - * @return a parsed version of the input or a default value. - */ - protected abstract Object sanitize( String context, String input ); - + /** + * The method is similar to ValidationRuile.getSafe except that it returns a + * harmless object that may or may not have any similarity to the original + * input (in some cases you may not care). In most cases this should be the + * same as the getSafe method only instead of throwing an exception, return + * some default value. + * + * @param context + * @param input + * @return a parsed version of the input or a default value. + */ + protected abstract Object sanitize( String context, String input ); + /** * {@inheritDoc} - */ - public boolean isValid( String context, String input ) { - boolean valid = false; - try { - getValid( context, input ); - valid = true; - } catch( Exception e ) { - valid = false; - } - - return valid; - } + */ + public boolean isValid( String context, String input ) { + boolean valid = false; + try { + getValid( context, input ); + valid = true; + } catch( Exception e ) { + valid = false; + } + + return valid; + } /** * {@inheritDoc} - */ - public String whitelist( String input, char[] whitelist) { - return whitelist(input, charArrayToSet(whitelist)); - } - - /** - * Removes characters that aren't in the whitelist from the input String. - * O(input.length) whitelist performance - * @param input String to be sanitized - * @param whitelist allowed characters - * @return input stripped of all chars that aren't in the whitelist - */ - public String whitelist( String input, Set whitelist) { - StringBuilder stripped = new StringBuilder(); - for (int i = 0; i < input.length(); i++) { - char c = input.charAt(i); - if (whitelist.contains(c)) { - stripped.append(c); - } - } - return stripped.toString(); - } - - // CHECKME should be moved to some utility class (Would potentially be used by new EncoderConstants class) - // Is there a standard way to convert an array of primitives to a Collection - /** - * Convert an array of characters to a {@code Set} (so duplicates - * are removed). - * @param array The character array. - * @return A {@code Set} of the unique characters from {@code array} - * is returned. - */ - public static Set charArrayToSet(char[] array) { - Set toReturn = new HashSet(array.length); - for (char c : array) { - toReturn.add(c); - } - return toReturn; - } - - public boolean isAllowNull() { - return allowNull; - } + */ + public String whitelist( String input, char[] whitelist) { + return whitelist(input, charArrayToSet(whitelist)); + } + + /** + * Removes characters that aren't in the whitelist from the input String. + * O(input.length) whitelist performance + * @param input String to be sanitized + * @param whitelist allowed characters + * @return input stripped of all chars that aren't in the whitelist + */ + public String whitelist( String input, Set whitelist) { + StringBuilder stripped = new StringBuilder(); + for (int i = 0; i < input.length(); i++) { + char c = input.charAt(i); + if (whitelist.contains(c)) { + stripped.append(c); + } + } + return stripped.toString(); + } + + // CHECKME should be moved to some utility class (Would potentially be used by new EncoderConstants class) + // Is there a standard way to convert an array of primitives to a Collection + /** + * Convert an array of characters to a {@code Set} (so duplicates + * are removed). + * @param array The character array. + * @return A {@code Set} of the unique characters from {@code array} + * is returned. + */ + public static Set charArrayToSet(char[] array) { + Set toReturn = new HashSet(array.length); + for (char c : array) { + toReturn.add(c); + } + return toReturn; + } + + public boolean isAllowNull() { + return allowNull; + } - public Encoder getEncoder() { - return encoder; - } + public Encoder getEncoder() { + return encoder; + } } diff --git a/src/main/java/org/owasp/esapi/reference/validation/CreditCardValidationRule.java b/src/main/java/org/owasp/esapi/reference/validation/CreditCardValidationRule.java index 008f1a19a..dea2a6370 100644 --- a/src/main/java/org/owasp/esapi/reference/validation/CreditCardValidationRule.java +++ b/src/main/java/org/owasp/esapi/reference/validation/CreditCardValidationRule.java @@ -33,133 +33,133 @@ * @see org.owasp.esapi.Validator */ public class CreditCardValidationRule extends BaseValidationRule { - private int maxCardLength = 19; - - /** - * Key used to pull out encoder in configuration. Prefixed with "Validator." - */ - protected static final String CREDIT_CARD_VALIDATOR_KEY = "CreditCard"; - - private StringValidationRule ccrule = null; - - /** - * Creates a CreditCardValidator using the rule found in security configuration - * @param typeName a description of the type of card being validated - * @param encoder - */ - public CreditCardValidationRule( String typeName, Encoder encoder ) { - super( typeName, encoder ); - ccrule = readDefaultCreditCardRule(); - } - - public CreditCardValidationRule( String typeName, Encoder encoder, StringValidationRule validationRule ) { - super( typeName, encoder ); - ccrule = validationRule; - } + private int maxCardLength = 19; + + /** + * Key used to pull out encoder in configuration. Prefixed with "Validator." + */ + protected static final String CREDIT_CARD_VALIDATOR_KEY = "CreditCard"; + + private StringValidationRule ccrule = null; + + /** + * Creates a CreditCardValidator using the rule found in security configuration + * @param typeName a description of the type of card being validated + * @param encoder + */ + public CreditCardValidationRule( String typeName, Encoder encoder ) { + super( typeName, encoder ); + ccrule = readDefaultCreditCardRule(); + } + + public CreditCardValidationRule( String typeName, Encoder encoder, StringValidationRule validationRule ) { + super( typeName, encoder ); + ccrule = validationRule; + } - private StringValidationRule readDefaultCreditCardRule() { - Pattern p = ESAPI.securityConfiguration().getValidationPattern( CREDIT_CARD_VALIDATOR_KEY ); - StringValidationRule ccr = new StringValidationRule( "ccrule", encoder, p.pattern() ); - ccr.setMaximumLength(getMaxCardLength()); - ccr.setAllowNull( false ); - return ccr; - } - + private StringValidationRule readDefaultCreditCardRule() { + Pattern p = ESAPI.securityConfiguration().getValidationPattern( CREDIT_CARD_VALIDATOR_KEY ); + StringValidationRule ccr = new StringValidationRule( "ccrule", encoder, p.pattern() ); + ccr.setMaximumLength(getMaxCardLength()); + ccr.setAllowNull( false ); + return ccr; + } + /** * {@inheritDoc} */ - public String getValid( String context, String input ) throws ValidationException { - // CHECKME should this allow empty Strings? " " us IsBlank instead? - if ( StringUtilities.isEmpty(input) ) { - if (allowNull) { - return null; - } - throw new ValidationException( context + ": Input credit card required", "Input credit card required: context=" + context + ", input=" + input, context ); - } - - String canonical = ccrule.getValid( context, input ); + public String getValid( String context, String input ) throws ValidationException { + // CHECKME should this allow empty Strings? " " us IsBlank instead? + if ( StringUtilities.isEmpty(input) ) { + if (allowNull) { + return null; + } + throw new ValidationException( context + ": Input credit card required", "Input credit card required: context=" + context + ", input=" + input, context ); + } + + String canonical = ccrule.getValid( context, input ); - if( ! validCreditCardFormat(canonical)) { - throw new ValidationException( context + ": Invalid credit card input", "Invalid credit card input: context=" + context, context ); - } - - return canonical; - } + if( ! validCreditCardFormat(canonical)) { + throw new ValidationException( context + ": Invalid credit card input", "Invalid credit card input: context=" + context, context ); + } + + return canonical; + } - /** - * Performs additional validation on the card nummber. - * This implementation performs Luhn algorithm checking - * @param ccNum number to be validated - * @return true if the ccNum passes the Luhn Algorithm - */ - protected boolean validCreditCardFormat(String ccNum) { - - StringBuilder digitsOnly = new StringBuilder(); - char c; - for (int i = 0; i < ccNum.length(); i++) { - c = ccNum.charAt(i); - if (Character.isDigit(c)) { - digitsOnly.append(c); - } - } - - int sum = 0; - int digit = 0; - int addend = 0; - boolean timesTwo = false; - - for (int i = digitsOnly.length() - 1; i >= 0; i--) { - // guaranteed to be an int - digit = Integer.valueOf(digitsOnly.substring(i, i + 1)); - if (timesTwo) { - addend = digit * 2; - if (addend > 9) { - addend -= 9; - } - } else { - addend = digit; - } - sum += addend; - timesTwo = !timesTwo; - } + /** + * Performs additional validation on the card nummber. + * This implementation performs Luhn algorithm checking + * @param ccNum number to be validated + * @return true if the ccNum passes the Luhn Algorithm + */ + protected boolean validCreditCardFormat(String ccNum) { + + StringBuilder digitsOnly = new StringBuilder(); + char c; + for (int i = 0; i < ccNum.length(); i++) { + c = ccNum.charAt(i); + if (Character.isDigit(c)) { + digitsOnly.append(c); + } + } + + int sum = 0; + int digit = 0; + int addend = 0; + boolean timesTwo = false; + + for (int i = digitsOnly.length() - 1; i >= 0; i--) { + // guaranteed to be an int + digit = Integer.valueOf(digitsOnly.substring(i, i + 1)); + if (timesTwo) { + addend = digit * 2; + if (addend > 9) { + addend -= 9; + } + } else { + addend = digit; + } + sum += addend; + timesTwo = !timesTwo; + } - return sum % 10 == 0; - - } - + return sum % 10 == 0; + + } + /** * {@inheritDoc} */ - @Override - public String sanitize( String context, String input ) { - return whitelist( input, EncoderConstants.CHAR_DIGITS ); - } + @Override + public String sanitize( String context, String input ) { + return whitelist( input, EncoderConstants.CHAR_DIGITS ); + } - /** - * @param ccrule the ccrule to set - */ - public void setStringValidatorRule(StringValidationRule ccrule) { - this.ccrule = ccrule; - } + /** + * @param ccrule the ccrule to set + */ + public void setStringValidatorRule(StringValidationRule ccrule) { + this.ccrule = ccrule; + } - /** - * @return the ccrule - */ - public StringValidationRule getStringValidatorRule() { - return ccrule; - } + /** + * @return the ccrule + */ + public StringValidationRule getStringValidatorRule() { + return ccrule; + } - /** - * @param maxCardLength the maxCardLength to set - */ - public void setMaxCardLength(int maxCardLength) { - this.maxCardLength = maxCardLength; - } + /** + * @param maxCardLength the maxCardLength to set + */ + public void setMaxCardLength(int maxCardLength) { + this.maxCardLength = maxCardLength; + } - /** - * @return the maxCardLength - */ - public int getMaxCardLength() { - return maxCardLength; - } + /** + * @return the maxCardLength + */ + public int getMaxCardLength() { + return maxCardLength; + } } diff --git a/src/main/java/org/owasp/esapi/reference/validation/DateValidationRule.java b/src/main/java/org/owasp/esapi/reference/validation/DateValidationRule.java index dd600d84e..b890b92be 100644 --- a/src/main/java/org/owasp/esapi/reference/validation/DateValidationRule.java +++ b/src/main/java/org/owasp/esapi/reference/validation/DateValidationRule.java @@ -34,24 +34,24 @@ * @see org.owasp.esapi.Validator */ public class DateValidationRule extends BaseValidationRule { - private DateFormat format = DateFormat.getDateInstance(); - - public DateValidationRule( String typeName, Encoder encoder, DateFormat newFormat ) { - super( typeName, encoder ); - setDateFormat( newFormat ); - } - + private DateFormat format = DateFormat.getDateInstance(); + + public DateValidationRule( String typeName, Encoder encoder, DateFormat newFormat ) { + super( typeName, encoder ); + setDateFormat( newFormat ); + } + public final void setDateFormat( DateFormat newFormat ) { if (newFormat == null) { - throw new IllegalArgumentException("DateValidationRule.setDateFormat requires a non-null DateFormat"); - } - // CHECKME fail fast? -/* - try { - newFormat.parse(new Date()); - } catch (ParseException e) { - throw new IllegalArgumentException(e); - } + throw new IllegalArgumentException("DateValidationRule.setDateFormat requires a non-null DateFormat"); + } + // CHECKME fail fast? +/* + try { + newFormat.parse(new Date()); + } catch (ParseException e) { + throw new IllegalArgumentException(e); + } */ this.format = newFormat; this.format.setLenient( ESAPI.securityConfiguration().getLenientDatesAccepted() ); @@ -60,19 +60,19 @@ public final void setDateFormat( DateFormat newFormat ) { /** * {@inheritDoc} */ - public Date getValid( String context, String input ) throws ValidationException { - return safelyParse(context, input, false); - } + public Date getValid( String context, String input ) throws ValidationException { + return safelyParse(context, input, false); + } /** * {@inheritDoc} */ - @Override - public Date sanitize( String context, String input ) { - return sanitize(context, input, null); - } - - /** + @Override + public Date sanitize( String context, String input ) { + return sanitize(context, input, null); + } + + /** * Same as sanitize(String, String) except it returns any ValidationException generated in the provided errorList. * * @param errorList The error list to add any ValidationException to. @@ -89,35 +89,35 @@ public Date sanitize( String context, String input, ValidationErrorList errorLis } return date; } - - private Date safelyParse(String context, String input, boolean sanitize) - throws ValidationException { - // CHECKME should this allow empty Strings? " " use IsBlank instead? - if (StringUtilities.isEmpty(input)) { - if (allowNull) { - return null; - } - throw new ValidationException(context + ": Input date required", - "Input date required: context=" + context + ", input=" - + input, context); - } + + private Date safelyParse(String context, String input, boolean sanitize) + throws ValidationException { + // CHECKME should this allow empty Strings? " " use IsBlank instead? + if (StringUtilities.isEmpty(input)) { + if (allowNull) { + return null; + } + throw new ValidationException(context + ": Input date required", + "Input date required: context=" + context + ", input=" + + input, context); + } - String canonical = encoder.canonicalize(input); - try { - Date rval = format.parse(canonical); - if (sanitize) { - String cycled = format.format(rval); - if (!cycled.equals(canonical)) { - throw new Exception("Parameter date is not a clean translation between String and Date contexts. Check input for additional characters"); - } - } - return rval; - } catch (Exception e) { - throw new ValidationException(context - + ": Invalid date must follow the " - + format.getNumberFormat() + " format", - "Invalid date: context=" + context + ", format=" + format - + ", input=" + input, e, context); - } - } + String canonical = encoder.canonicalize(input); + try { + Date rval = format.parse(canonical); + if (sanitize) { + String cycled = format.format(rval); + if (!cycled.equals(canonical)) { + throw new Exception("Parameter date is not a clean translation between String and Date contexts. Check input for additional characters"); + } + } + return rval; + } catch (Exception e) { + throw new ValidationException(context + + ": Invalid date must follow the " + + format.getNumberFormat() + " format", + "Invalid date: context=" + context + ", format=" + format + + ", input=" + input, e, context); + } + } } diff --git a/src/main/java/org/owasp/esapi/reference/validation/HTMLValidationRule.java b/src/main/java/org/owasp/esapi/reference/validation/HTMLValidationRule.java index a1e725f00..41e60e697 100644 --- a/src/main/java/org/owasp/esapi/reference/validation/HTMLValidationRule.java +++ b/src/main/java/org/owasp/esapi/reference/validation/HTMLValidationRule.java @@ -49,62 +49,62 @@ */ public class HTMLValidationRule extends StringValidationRule { - /** OWASP AntiSamy markup verification policy */ - private static Policy antiSamyPolicy = null; - private static final Logger LOGGER = ESAPI.getLogger( "HTMLValidationRule" ); - private static final String ANTISAMYPOLICY_FILENAME = "antisamy-esapi.xml"; + /** OWASP AntiSamy markup verification policy */ + private static Policy antiSamyPolicy = null; + private static final Logger LOGGER = ESAPI.getLogger( "HTMLValidationRule" ); + private static final String ANTISAMYPOLICY_FILENAME = "antisamy-esapi.xml"; - /*package */ static InputStream getResourceStreamFromClassLoader(String contextDescription, ClassLoader classLoader, String fileName, List searchPaths) { - InputStream result = null; - - for (String searchPath: searchPaths) { - result = classLoader.getResourceAsStream(searchPath + fileName); - - if (result != null) { - LOGGER.info(Logger.EVENT_SUCCESS, "SUCCESSFULLY LOADED " + fileName + " via the CLASSPATH from '" + - searchPath + "' using " + contextDescription + "!"); - break; - } - } - - return result; - } - - /*package */ static InputStream getResourceStreamFromClasspath(String fileName) { - LOGGER.info(Logger.EVENT_FAILURE, "Loading " + fileName + " from classpaths"); - - InputStream resourceStream = null; - - List orderedSearchPaths = Arrays.asList(DefaultSearchPath.ROOT.value(), - DefaultSearchPath.RESOURCE_DIRECTORY.value(), - DefaultSearchPath.DOT_ESAPI.value(), - DefaultSearchPath.ESAPI.value(), - DefaultSearchPath.RESOURCES.value(), - DefaultSearchPath.SRC_MAIN_RESOURCES.value()); - - resourceStream = getResourceStreamFromClassLoader("current thread context class loader", Thread.currentThread().getContextClassLoader(), fileName, orderedSearchPaths); - - //I'm lazy. Using ternary for shorthand "if null then do next thing" Harder to read, sorry - resourceStream = resourceStream != null ? resourceStream : getResourceStreamFromClassLoader("system class loader", ClassLoader.getSystemClassLoader(), fileName, orderedSearchPaths); - resourceStream = resourceStream != null ? resourceStream : getResourceStreamFromClassLoader("class loader for DefaultSecurityConfiguration class", ESAPI.securityConfiguration().getClass().getClassLoader(), fileName, orderedSearchPaths); - - return resourceStream; - } - - /*package */ static Policy loadAntisamyPolicy(String antisamyPolicyFilename) throws IOException, PolicyException { - InputStream resourceStream = null; - SecurityConfiguration secCfg = ESAPI.securityConfiguration(); - - //Rather than catching the IOException from the resource stream, let's ask if the file exists to give this a best-case resolution. - //This helps with the IOException handling too. If the file is there and we get an IOException from the SecurityConfiguration, then the file is there and something else is wrong (FAIL -- don't try the other path) - File file = secCfg.getResourceFile(antisamyPolicyFilename); + /*package */ static InputStream getResourceStreamFromClassLoader(String contextDescription, ClassLoader classLoader, String fileName, List searchPaths) { + InputStream result = null; + + for (String searchPath: searchPaths) { + result = classLoader.getResourceAsStream(searchPath + fileName); + + if (result != null) { + LOGGER.info(Logger.EVENT_SUCCESS, "SUCCESSFULLY LOADED " + fileName + " via the CLASSPATH from '" + + searchPath + "' using " + contextDescription + "!"); + break; + } + } + + return result; + } + + /*package */ static InputStream getResourceStreamFromClasspath(String fileName) { + LOGGER.info(Logger.EVENT_FAILURE, "Loading " + fileName + " from classpaths"); + + InputStream resourceStream = null; + + List orderedSearchPaths = Arrays.asList(DefaultSearchPath.ROOT.value(), + DefaultSearchPath.RESOURCE_DIRECTORY.value(), + DefaultSearchPath.DOT_ESAPI.value(), + DefaultSearchPath.ESAPI.value(), + DefaultSearchPath.RESOURCES.value(), + DefaultSearchPath.SRC_MAIN_RESOURCES.value()); + + resourceStream = getResourceStreamFromClassLoader("current thread context class loader", Thread.currentThread().getContextClassLoader(), fileName, orderedSearchPaths); + + //I'm lazy. Using ternary for shorthand "if null then do next thing" Harder to read, sorry + resourceStream = resourceStream != null ? resourceStream : getResourceStreamFromClassLoader("system class loader", ClassLoader.getSystemClassLoader(), fileName, orderedSearchPaths); + resourceStream = resourceStream != null ? resourceStream : getResourceStreamFromClassLoader("class loader for DefaultSecurityConfiguration class", ESAPI.securityConfiguration().getClass().getClassLoader(), fileName, orderedSearchPaths); + + return resourceStream; + } + + /*package */ static Policy loadAntisamyPolicy(String antisamyPolicyFilename) throws IOException, PolicyException { + InputStream resourceStream = null; + SecurityConfiguration secCfg = ESAPI.securityConfiguration(); + + //Rather than catching the IOException from the resource stream, let's ask if the file exists to give this a best-case resolution. + //This helps with the IOException handling too. If the file is there and we get an IOException from the SecurityConfiguration, then the file is there and something else is wrong (FAIL -- don't try the other path) + File file = secCfg.getResourceFile(antisamyPolicyFilename); resourceStream = file == null ? getResourceStreamFromClasspath(antisamyPolicyFilename) : secCfg.getResourceStream(antisamyPolicyFilename); return resourceStream == null ? null : Policy.getInstance(resourceStream); - } + } - /*package */ static String resolveAntisamyFilename() { - String antisamyPolicyFilename = ANTISAMYPOLICY_FILENAME; + /*package */ static String resolveAntisamyFilename() { + String antisamyPolicyFilename = ANTISAMYPOLICY_FILENAME; try { antisamyPolicyFilename = ESAPI.securityConfiguration().getStringProp( // Future: This will be moved to a new PropNames class @@ -116,10 +116,10 @@ public class HTMLValidationRule extends StringValidationRule { " not set, using default value: " + ANTISAMYPOLICY_FILENAME); } return antisamyPolicyFilename; - } - - /*package */ static void configureInstance() { - String antisamyPolicyFilename = resolveAntisamyFilename(); + } + + /*package */ static void configureInstance() { + String antisamyPolicyFilename = resolveAntisamyFilename(); try { antiSamyPolicy = loadAntisamyPolicy(antisamyPolicyFilename); @@ -135,45 +135,45 @@ public class HTMLValidationRule extends StringValidationRule { throw new ConfigurationException("Couldn't find " + antisamyPolicyFilename); } - } - - static { - configureInstance(); - } + } + + static { + configureInstance(); + } - public HTMLValidationRule( String typeName ) { - super( typeName ); - } + public HTMLValidationRule( String typeName ) { + super( typeName ); + } - public HTMLValidationRule( String typeName, Encoder encoder ) { - super( typeName, encoder ); - } + public HTMLValidationRule( String typeName, Encoder encoder ) { + super( typeName, encoder ); + } - public HTMLValidationRule( String typeName, Encoder encoder, String whitelistPattern ) { - super( typeName, encoder, whitelistPattern ); - } + public HTMLValidationRule( String typeName, Encoder encoder, String whitelistPattern ) { + super( typeName, encoder, whitelistPattern ); + } /** * {@inheritDoc} */ - @Override - public String getValid( String context, String input ) throws ValidationException { - return invokeAntiSamy( context, input ); - } + @Override + public String getValid( String context, String input ) throws ValidationException { + return invokeAntiSamy( context, input ); + } /** * {@inheritDoc} */ - @Override - public String sanitize( String context, String input ) { - String safe = ""; - try { - safe = invokeAntiSamy( context, input ); - } catch( ValidationException e ) { - // just return safe - } - return safe; - } + @Override + public String sanitize( String context, String input ) { + String safe = ""; + try { + safe = invokeAntiSamy( context, input ); + } catch( ValidationException e ) { + // just return safe + } + return safe; + } /** * Check whether we want the legacy behavior ("clean") or the presumably intended @@ -227,37 +227,37 @@ private boolean legacyHtmlValidation() { return legacy; } - private String invokeAntiSamy( String context, String input ) throws ValidationException { - // CHECKME should this allow empty Strings? " " use IsBlank instead? - if ( StringUtilities.isEmpty(input) ) { - if (allowNull) { - return null; - } - throw new ValidationException( context + " is required", "AntiSamy validation error: context=" + context + ", input=" + input, context ); - } + private String invokeAntiSamy( String context, String input ) throws ValidationException { + // CHECKME should this allow empty Strings? " " use IsBlank instead? + if ( StringUtilities.isEmpty(input) ) { + if (allowNull) { + return null; + } + throw new ValidationException( context + " is required", "AntiSamy validation error: context=" + context + ", input=" + input, context ); + } - String canonical = super.getValid( context, input ); + String canonical = super.getValid( context, input ); - try { - AntiSamy as = new AntiSamy(); - CleanResults test = as.scan(canonical, antiSamyPolicy); // Uses AntiSamy.DOM scanner. + try { + AntiSamy as = new AntiSamy(); + CleanResults test = as.scan(canonical, antiSamyPolicy); // Uses AntiSamy.DOM scanner. - List errors = test.getErrorMessages(); - if ( !errors.isEmpty() ) { + List errors = test.getErrorMessages(); + if ( !errors.isEmpty() ) { if ( legacyHtmlValidation() ) { // See GitHub issues 509 and 521 LOGGER.info(Logger.SECURITY_FAILURE, "Cleaned up invalid HTML input: " + errors ); } else { - throw new ValidationException( context + ": Invalid HTML input", "Invalid HTML input does not follow rules in antisamy-esapi.xml: context=" + context + " errors=" + errors.toString()); + throw new ValidationException( context + ": Invalid HTML input", "Invalid HTML input does not follow rules in antisamy-esapi.xml: context=" + context + " errors=" + errors.toString()); } - } + } - return test.getCleanHTML().trim(); + return test.getCleanHTML().trim(); - } catch (ScanException e) { - throw new ValidationException( context + ": Invalid HTML input", "Invalid HTML input: context=" + context + " error=" + e.getMessage(), e, context ); - } catch (PolicyException e) { - throw new ValidationException( context + ": Invalid HTML input", "Invalid HTML input does not follow rules in antisamy-esapi.xml: context=" + context + " error=" + e.getMessage(), e, context ); - } - } + } catch (ScanException e) { + throw new ValidationException( context + ": Invalid HTML input", "Invalid HTML input: context=" + context + " error=" + e.getMessage(), e, context ); + } catch (PolicyException e) { + throw new ValidationException( context + ": Invalid HTML input", "Invalid HTML input does not follow rules in antisamy-esapi.xml: context=" + context + " error=" + e.getMessage(), e, context ); + } + } } diff --git a/src/main/java/org/owasp/esapi/reference/validation/IntegerValidationRule.java b/src/main/java/org/owasp/esapi/reference/validation/IntegerValidationRule.java index e01037723..6f99197fd 100644 --- a/src/main/java/org/owasp/esapi/reference/validation/IntegerValidationRule.java +++ b/src/main/java/org/owasp/esapi/reference/validation/IntegerValidationRule.java @@ -30,66 +30,66 @@ * @see org.owasp.esapi.Validator */ public class IntegerValidationRule extends BaseValidationRule { - - private int minValue = Integer.MIN_VALUE; - private int maxValue = Integer.MAX_VALUE; - - public IntegerValidationRule( String typeName, Encoder encoder ) { - super( typeName, encoder ); - } + + private int minValue = Integer.MIN_VALUE; + private int maxValue = Integer.MAX_VALUE; + + public IntegerValidationRule( String typeName, Encoder encoder ) { + super( typeName, encoder ); + } - public IntegerValidationRule( String typeName, Encoder encoder, int minValue, int maxValue ) { - super( typeName, encoder ); - this.minValue = minValue; - this.maxValue = maxValue; - } + public IntegerValidationRule( String typeName, Encoder encoder, int minValue, int maxValue ) { + super( typeName, encoder ); + this.minValue = minValue; + this.maxValue = maxValue; + } - public Integer getValid( String context, String input ) throws ValidationException { - return safelyParse(context, input); - } + public Integer getValid( String context, String input ) throws ValidationException { + return safelyParse(context, input); + } - private Integer safelyParse(String context, String input) throws ValidationException { - // do not allow empty Strings such as " " - so trim to ensure - // isEmpty catches " " - if (input != null) input = input.trim(); - - if ( StringUtilities.isEmpty(input) ) { - if (allowNull) { - return null; - } - throw new ValidationException( context + ": Input number required", "Input number required: context=" + context + ", input=" + input, context ); - } - - // canonicalize - String canonical = encoder.canonicalize( input ); + private Integer safelyParse(String context, String input) throws ValidationException { + // do not allow empty Strings such as " " - so trim to ensure + // isEmpty catches " " + if (input != null) input = input.trim(); + + if ( StringUtilities.isEmpty(input) ) { + if (allowNull) { + return null; + } + throw new ValidationException( context + ": Input number required", "Input number required: context=" + context + ", input=" + input, context ); + } + + // canonicalize + String canonical = encoder.canonicalize( input ); - if (minValue > maxValue) { - throw new ValidationException( context + ": Invalid number input: context", "Validation parameter error for number: maxValue ( " + maxValue + ") must be greater than minValue ( " + minValue + ") for " + context, context ); - } - - // validate min and max - try { - int i = Integer.valueOf(canonical); - if (i < minValue) { - throw new ValidationException( "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context, "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context + ", input=" + input, context ); - } - if (i > maxValue) { - throw new ValidationException( "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context, "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context + ", input=" + input, context ); - } - return i; - } catch (NumberFormatException e) { - throw new ValidationException( context + ": Invalid number input", "Invalid number input format: context=" + context + ", input=" + input, e, context); - } - } + if (minValue > maxValue) { + throw new ValidationException( context + ": Invalid number input: context", "Validation parameter error for number: maxValue ( " + maxValue + ") must be greater than minValue ( " + minValue + ") for " + context, context ); + } + + // validate min and max + try { + int i = Integer.valueOf(canonical); + if (i < minValue) { + throw new ValidationException( "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context, "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context + ", input=" + input, context ); + } + if (i > maxValue) { + throw new ValidationException( "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context, "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context + ", input=" + input, context ); + } + return i; + } catch (NumberFormatException e) { + throw new ValidationException( context + ": Invalid number input", "Invalid number input format: context=" + context + ", input=" + input, e, context); + } + } - @Override - public Integer sanitize( String context, String input ) { - Integer toReturn = Integer.valueOf( 0 ); - try { - toReturn = safelyParse(context, input); - } catch (ValidationException e ) { - // do nothing - } - return toReturn; - } + @Override + public Integer sanitize( String context, String input ) { + Integer toReturn = Integer.valueOf( 0 ); + try { + toReturn = safelyParse(context, input); + } catch (ValidationException e ) { + // do nothing + } + return toReturn; + } } \ No newline at end of file diff --git a/src/main/java/org/owasp/esapi/reference/validation/NumberValidationRule.java b/src/main/java/org/owasp/esapi/reference/validation/NumberValidationRule.java index b5933a31f..0d83a5746 100644 --- a/src/main/java/org/owasp/esapi/reference/validation/NumberValidationRule.java +++ b/src/main/java/org/owasp/esapi/reference/validation/NumberValidationRule.java @@ -32,115 +32,115 @@ * @see org.owasp.esapi.Validator */ public class NumberValidationRule extends BaseValidationRule { - - private double minValue = Double.NEGATIVE_INFINITY; - private double maxValue = Double.POSITIVE_INFINITY; - - public NumberValidationRule( String typeName, Encoder encoder ) { - super( typeName, encoder ); - } + + private double minValue = Double.NEGATIVE_INFINITY; + private double maxValue = Double.POSITIVE_INFINITY; + + public NumberValidationRule( String typeName, Encoder encoder ) { + super( typeName, encoder ); + } - public NumberValidationRule( String typeName, Encoder encoder, double minValue, double maxValue ) { - super( typeName, encoder ); - this.minValue = minValue; - this.maxValue = maxValue; - } + public NumberValidationRule( String typeName, Encoder encoder, double minValue, double maxValue ) { + super( typeName, encoder ); + this.minValue = minValue; + this.maxValue = maxValue; + } /** * {@inheritDoc} */ - public Double getValid( String context, String input ) throws ValidationException { - return safelyParse(context, input); - } - + public Double getValid( String context, String input ) throws ValidationException { + return safelyParse(context, input); + } + /** * {@inheritDoc} */ - @Override - public Double sanitize( String context, String input ) { - Double toReturn = Double.valueOf(0); - try { - toReturn = safelyParse(context, input); - } catch (ValidationException e) { - // do nothing - } - return toReturn; - } - // - // These statics needed to detect double parsing DOS bug in Java - // - private static BigDecimal bigBad; - private static BigDecimal smallBad; + @Override + public Double sanitize( String context, String input ) { + Double toReturn = Double.valueOf(0); + try { + toReturn = safelyParse(context, input); + } catch (ValidationException e) { + // do nothing + } + return toReturn; + } + // + // These statics needed to detect double parsing DOS bug in Java + // + private static BigDecimal bigBad; + private static BigDecimal smallBad; - static { - - BigDecimal one = new BigDecimal(1); - BigDecimal two = new BigDecimal(2); - - BigDecimal tiny = one.divide(two.pow(1022)); - - // 2^(-1022) ­ 2^(-1076) - bigBad = tiny.subtract(one.divide(two.pow(1076))); - //2^(-1022) ­ 2^(-1075) - smallBad = tiny.subtract(one.divide(two.pow(1075))); - } + static { + + BigDecimal one = new BigDecimal(1); + BigDecimal two = new BigDecimal(2); + + BigDecimal tiny = one.divide(two.pow(1022)); + + // 2^(-1022) ­ 2^(-1076) + bigBad = tiny.subtract(one.divide(two.pow(1076))); + //2^(-1022) ­ 2^(-1075) + smallBad = tiny.subtract(one.divide(two.pow(1075))); + } - private Double safelyParse(String context, String input) throws ValidationException { + private Double safelyParse(String context, String input) throws ValidationException { - // CHECKME should this allow empty Strings? " " us IsBlank instead? - if ( StringUtilities.isEmpty(input) ) { - if (allowNull) { - return null; - } - throw new ValidationException( context + ": Input number required", "Input number required: context=" + context + ", input=" + input, context ); - } - - // canonicalize - String canonical = encoder.canonicalize( input ); + // CHECKME should this allow empty Strings? " " us IsBlank instead? + if ( StringUtilities.isEmpty(input) ) { + if (allowNull) { + return null; + } + throw new ValidationException( context + ": Input number required", "Input number required: context=" + context + ", input=" + input, context ); + } + + // canonicalize + String canonical = encoder.canonicalize( input ); - //if MinValue is greater than maxValue then programmer is likely calling this wrong - if (minValue > maxValue) { - throw new ValidationException( context + ": Invalid number input: context", "Validation parameter error for number: maxValue ( " + maxValue + ") must be greater than minValue ( " + minValue + ") for " + context, context ); - } - - //convert to BigDecimal so we can safely parse dangerous numbers to - //check if the number may DOS the double parser - BigDecimal bd; - try { - bd = new BigDecimal(canonical); - } catch (NumberFormatException e) { - throw new ValidationException( context + ": Invalid number input", "Invalid number input format: context=" + context + ", input=" + input, e, context); - } - - // Thanks to Brian Chess for this suggestion - // Check if string input is in the "dangerous" double parsing range - if (bd.compareTo(smallBad) >= 0 && bd.compareTo(bigBad) <= 0) { - // if you get here you know you're looking at a bad value. The final - // value for any double in this range is supposed to be the following safe # - return new Double("2.2250738585072014E-308"); - } - - // the number is safe to parseDouble - Double d; - // validate min and max - try { - d = Double.valueOf(Double.parseDouble( canonical )); - } catch (NumberFormatException e) { - throw new ValidationException( context + ": Invalid number input", "Invalid number input format: context=" + context + ", input=" + input, e, context); - } - - if (d.isInfinite()) { - throw new ValidationException( "Invalid number input: context=" + context, "Invalid double input is infinite: context=" + context + ", input=" + input, context ); - } - if (d.isNaN()) { - throw new ValidationException( "Invalid number input: context=" + context, "Invalid double input is not a number: context=" + context + ", input=" + input, context ); - } - if (d.doubleValue() < minValue) { - throw new ValidationException( "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context, "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context + ", input=" + input, context ); - } - if (d.doubleValue() > maxValue) { - throw new ValidationException( "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context, "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context + ", input=" + input, context ); - } - return d; - } + //if MinValue is greater than maxValue then programmer is likely calling this wrong + if (minValue > maxValue) { + throw new ValidationException( context + ": Invalid number input: context", "Validation parameter error for number: maxValue ( " + maxValue + ") must be greater than minValue ( " + minValue + ") for " + context, context ); + } + + //convert to BigDecimal so we can safely parse dangerous numbers to + //check if the number may DOS the double parser + BigDecimal bd; + try { + bd = new BigDecimal(canonical); + } catch (NumberFormatException e) { + throw new ValidationException( context + ": Invalid number input", "Invalid number input format: context=" + context + ", input=" + input, e, context); + } + + // Thanks to Brian Chess for this suggestion + // Check if string input is in the "dangerous" double parsing range + if (bd.compareTo(smallBad) >= 0 && bd.compareTo(bigBad) <= 0) { + // if you get here you know you're looking at a bad value. The final + // value for any double in this range is supposed to be the following safe # + return new Double("2.2250738585072014E-308"); + } + + // the number is safe to parseDouble + Double d; + // validate min and max + try { + d = Double.valueOf(Double.parseDouble( canonical )); + } catch (NumberFormatException e) { + throw new ValidationException( context + ": Invalid number input", "Invalid number input format: context=" + context + ", input=" + input, e, context); + } + + if (d.isInfinite()) { + throw new ValidationException( "Invalid number input: context=" + context, "Invalid double input is infinite: context=" + context + ", input=" + input, context ); + } + if (d.isNaN()) { + throw new ValidationException( "Invalid number input: context=" + context, "Invalid double input is not a number: context=" + context + ", input=" + input, context ); + } + if (d.doubleValue() < minValue) { + throw new ValidationException( "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context, "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context + ", input=" + input, context ); + } + if (d.doubleValue() > maxValue) { + throw new ValidationException( "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context, "Invalid number input must be between " + minValue + " and " + maxValue + ": context=" + context + ", input=" + input, context ); + } + return d; + } } diff --git a/src/main/java/org/owasp/esapi/reference/validation/StringValidationRule.java b/src/main/java/org/owasp/esapi/reference/validation/StringValidationRule.java index 11fea3112..16c607cfa 100644 --- a/src/main/java/org/owasp/esapi/reference/validation/StringValidationRule.java +++ b/src/main/java/org/owasp/esapi/reference/validation/StringValidationRule.java @@ -42,260 +42,260 @@ */ public class StringValidationRule extends BaseValidationRule { private static final Logger LOGGER = ESAPI.getLogger(StringValidationRule.class); - protected List whitelistPatterns = new ArrayList(); - protected List blacklistPatterns = new ArrayList(); - protected int minLength = 0; - protected int maxLength = Integer.MAX_VALUE; - private boolean canonicalizeInput = true; - - public StringValidationRule( String typeName ) { - super( typeName ); - } - - public StringValidationRule( String typeName, Encoder encoder ) { - super( typeName, encoder ); - } - - public StringValidationRule( String typeName, Encoder encoder, String whitelistPattern ) { - super( typeName, encoder ); - addWhitelistPattern( whitelistPattern ); - } - - /** - * @throws IllegalArgumentException if pattern is null - */ - public void addWhitelistPattern( String pattern ) { - if (pattern == null) { - throw new IllegalArgumentException("Pattern cannot be null"); - } - try { - whitelistPatterns.add( Pattern.compile( pattern ) ); - } catch( PatternSyntaxException e ) { - throw new IllegalArgumentException( "Validation misconfiguration, problem with specified pattern: " + pattern, e ); - } - } - - /** - * @throws IllegalArgumentException if p is null - */ - public void addWhitelistPattern( Pattern p ) { - if (p == null) { - throw new IllegalArgumentException("Pattern cannot be null"); - } - whitelistPatterns.add( p ); - } - - /** - * @throws IllegalArgumentException if pattern is null - */ - public void addBlacklistPattern( String pattern ) { - if (pattern == null) { - throw new IllegalArgumentException("Pattern cannot be null"); - } - try { - blacklistPatterns.add( Pattern.compile( pattern ) ); - } catch( PatternSyntaxException e ) { - throw new IllegalArgumentException( "Validation misconfiguration, problem with specified pattern: " + pattern, e ); - } - } - - /** - * @throws IllegalArgumentException if p is null - */ - public void addBlacklistPattern( Pattern p ) { - if (p == null) { - throw new IllegalArgumentException("Pattern cannot be null"); - } - blacklistPatterns.add( p ); - } - - public void setMinimumLength( int length ) { - minLength = length; - } - - - public void setMaximumLength( int length ) { - maxLength = length; - } - - public void setCanonicalize(boolean canonicalize) { - this.canonicalizeInput = canonicalize; - } - - /** - * checks input against whitelists. - * @param context The context to include in exception messages - * @param input the input to check - * @param orig A origional input to include in exception - * messages. This is not included if it is the same as - * input. - * @return input upon a successful check - * @throws ValidationException if the check fails. - */ - private String checkWhitelist(String context, String input, String orig) throws ValidationException - { - // check whitelist patterns - for (Pattern p : whitelistPatterns) { - if ( !p.matcher(input).matches() ) { - throw new ValidationException( context + ": Invalid input. Please conform to regex " + p.pattern() + ( maxLength == Integer.MAX_VALUE ? "" : " with a maximum length of " + maxLength ), "Invalid input: context=" + context + ", type(" + getTypeName() + ")=" + p.pattern() + ", input=" + input + (NullSafe.equals(orig,input) ? "" : ", orig=" + orig), context ); - } - } - - return input; - } - - /** - * checks input against whitelists. - * @param context The context to include in exception messages - * @param input the input to check - * @return input upon a successful check - * @throws ValidationException if the check fails. - */ - private String checkWhitelist(String context, String input) throws ValidationException - { - return checkWhitelist(context, input, input); - } - - /** - * checks input against blacklists. - * @param context The context to include in exception messages - * @param input the input to check - * @param orig A origional input to include in exception - * messages. This is not included if it is the same as - * input. - * @return input upon a successful check - * @throws ValidationException if the check fails. - */ - private String checkBlacklist(String context, String input, String orig) throws ValidationException - { - // check blacklist patterns - for (Pattern p : blacklistPatterns) { - if ( p.matcher(input).matches() ) { - throw new ValidationException( context + ": Invalid input. Dangerous input matching " + p.pattern() + " detected.", "Dangerous input: context=" + context + ", type(" + getTypeName() + ")=" + p.pattern() + ", input=" + input + (NullSafe.equals(orig,input) ? "" : ", orig=" + orig), context ); - } - } - - return input; - } - - /** - * checks input against blacklists. - * @param context The context to include in exception messages - * @param input the input to check - * @return input upon a successful check - * @throws ValidationException if the check fails. - */ - private String checkBlacklist(String context, String input) throws ValidationException - { - return checkBlacklist(context, input, input); - } - - /** - * checks input lengths - * @param context The context to include in exception messages - * @param input the input to check - * @param orig A origional input to include in exception - * messages. This is not included if it is the same as - * input. - * @return input upon a successful check - * @throws ValidationException if the check fails. - */ - private String checkLength(String context, String input, String orig) throws ValidationException - { - if (input.length() < minLength) { - throw new ValidationException( context + ": Invalid input. The minimum length of " + minLength + " characters was not met.", "Input does not meet the minimum length of " + minLength + " by " + (minLength - input.length()) + " characters: context=" + context + ", type=" + getTypeName() + "), input=" + input + (NullSafe.equals(input,orig) ? "" : ", orig=" + orig), context ); - } - - if (input.length() > maxLength) { - throw new ValidationException( context + ": Invalid input. The maximum length of " + maxLength + " characters was exceeded.", "Input exceeds maximum allowed length of " + maxLength + " by " + (input.length()-maxLength) + " characters: context=" + context + ", type=" + getTypeName() + ", orig=" + orig +", input=" + input, context ); - } - - return input; - } - - /** - * checks input lengths - * @param context The context to include in exception messages - * @param input the input to check - * @return input upon a successful check - * @throws ValidationException if the check fails. - */ - private String checkLength(String context, String input) throws ValidationException - { - return checkLength(context, input, input); - } - - /** - * checks input emptiness - * @param context The context to include in exception messages - * @param input the input to check - * @param orig A origional input to include in exception - * messages. This is not included if it is the same as - * input. - * @return input upon a successful check - * @throws ValidationException if the check fails. - */ - private String checkEmpty(String context, String input, String orig) throws ValidationException - { - if(!StringUtilities.isEmpty(input)) - return input; - if(allowNull) - return null; - throw new ValidationException( context + ": Input required.", "Input required: context=" + context + "), input=" + input + (NullSafe.equals(input,orig) ? "" : ", orig=" + orig), context ); - } - - /** - * checks input emptiness - * @param context The context to include in exception messages - * @param input the input to check - * @return input upon a successful check - * @throws ValidationException if the check fails. - */ - private String checkEmpty(String context, String input) throws ValidationException - { - return checkEmpty(context, input, input); - } - - /** - * {@inheritDoc} - */ - public String getValid( String context, String input ) throws ValidationException - { - String data = null; - - // check for empty/null - if(checkEmpty(context, input) == null) - return null; - - // check length - checkLength(context, input); - - // canonicalize - if (canonicalizeInput) { - data = encoder.canonicalize(input); - } else { - String message = String.format("Input validation excludes canonicalization. Context: %s Input: %s", context, input); - LOGGER.warning(Logger.SECURITY_AUDIT, message); + protected List whitelistPatterns = new ArrayList(); + protected List blacklistPatterns = new ArrayList(); + protected int minLength = 0; + protected int maxLength = Integer.MAX_VALUE; + private boolean canonicalizeInput = true; + + public StringValidationRule( String typeName ) { + super( typeName ); + } + + public StringValidationRule( String typeName, Encoder encoder ) { + super( typeName, encoder ); + } + + public StringValidationRule( String typeName, Encoder encoder, String whitelistPattern ) { + super( typeName, encoder ); + addWhitelistPattern( whitelistPattern ); + } + + /** + * @throws IllegalArgumentException if pattern is null + */ + public void addWhitelistPattern( String pattern ) { + if (pattern == null) { + throw new IllegalArgumentException("Pattern cannot be null"); + } + try { + whitelistPatterns.add( Pattern.compile( pattern ) ); + } catch( PatternSyntaxException e ) { + throw new IllegalArgumentException( "Validation misconfiguration, problem with specified pattern: " + pattern, e ); + } + } + + /** + * @throws IllegalArgumentException if p is null + */ + public void addWhitelistPattern( Pattern p ) { + if (p == null) { + throw new IllegalArgumentException("Pattern cannot be null"); + } + whitelistPatterns.add( p ); + } + + /** + * @throws IllegalArgumentException if pattern is null + */ + public void addBlacklistPattern( String pattern ) { + if (pattern == null) { + throw new IllegalArgumentException("Pattern cannot be null"); + } + try { + blacklistPatterns.add( Pattern.compile( pattern ) ); + } catch( PatternSyntaxException e ) { + throw new IllegalArgumentException( "Validation misconfiguration, problem with specified pattern: " + pattern, e ); + } + } + + /** + * @throws IllegalArgumentException if p is null + */ + public void addBlacklistPattern( Pattern p ) { + if (p == null) { + throw new IllegalArgumentException("Pattern cannot be null"); + } + blacklistPatterns.add( p ); + } + + public void setMinimumLength( int length ) { + minLength = length; + } + + + public void setMaximumLength( int length ) { + maxLength = length; + } + + public void setCanonicalize(boolean canonicalize) { + this.canonicalizeInput = canonicalize; + } + + /** + * checks input against whitelists. + * @param context The context to include in exception messages + * @param input the input to check + * @param orig A origional input to include in exception + * messages. This is not included if it is the same as + * input. + * @return input upon a successful check + * @throws ValidationException if the check fails. + */ + private String checkWhitelist(String context, String input, String orig) throws ValidationException + { + // check whitelist patterns + for (Pattern p : whitelistPatterns) { + if ( !p.matcher(input).matches() ) { + throw new ValidationException( context + ": Invalid input. Please conform to regex " + p.pattern() + ( maxLength == Integer.MAX_VALUE ? "" : " with a maximum length of " + maxLength ), "Invalid input: context=" + context + ", type(" + getTypeName() + ")=" + p.pattern() + ", input=" + input + (NullSafe.equals(orig,input) ? "" : ", orig=" + orig), context ); + } + } + + return input; + } + + /** + * checks input against whitelists. + * @param context The context to include in exception messages + * @param input the input to check + * @return input upon a successful check + * @throws ValidationException if the check fails. + */ + private String checkWhitelist(String context, String input) throws ValidationException + { + return checkWhitelist(context, input, input); + } + + /** + * checks input against blacklists. + * @param context The context to include in exception messages + * @param input the input to check + * @param orig A origional input to include in exception + * messages. This is not included if it is the same as + * input. + * @return input upon a successful check + * @throws ValidationException if the check fails. + */ + private String checkBlacklist(String context, String input, String orig) throws ValidationException + { + // check blacklist patterns + for (Pattern p : blacklistPatterns) { + if ( p.matcher(input).matches() ) { + throw new ValidationException( context + ": Invalid input. Dangerous input matching " + p.pattern() + " detected.", "Dangerous input: context=" + context + ", type(" + getTypeName() + ")=" + p.pattern() + ", input=" + input + (NullSafe.equals(orig,input) ? "" : ", orig=" + orig), context ); + } + } + + return input; + } + + /** + * checks input against blacklists. + * @param context The context to include in exception messages + * @param input the input to check + * @return input upon a successful check + * @throws ValidationException if the check fails. + */ + private String checkBlacklist(String context, String input) throws ValidationException + { + return checkBlacklist(context, input, input); + } + + /** + * checks input lengths + * @param context The context to include in exception messages + * @param input the input to check + * @param orig A origional input to include in exception + * messages. This is not included if it is the same as + * input. + * @return input upon a successful check + * @throws ValidationException if the check fails. + */ + private String checkLength(String context, String input, String orig) throws ValidationException + { + if (input.length() < minLength) { + throw new ValidationException( context + ": Invalid input. The minimum length of " + minLength + " characters was not met.", "Input does not meet the minimum length of " + minLength + " by " + (minLength - input.length()) + " characters: context=" + context + ", type=" + getTypeName() + "), input=" + input + (NullSafe.equals(input,orig) ? "" : ", orig=" + orig), context ); + } + + if (input.length() > maxLength) { + throw new ValidationException( context + ": Invalid input. The maximum length of " + maxLength + " characters was exceeded.", "Input exceeds maximum allowed length of " + maxLength + " by " + (input.length()-maxLength) + " characters: context=" + context + ", type=" + getTypeName() + ", orig=" + orig +", input=" + input, context ); + } + + return input; + } + + /** + * checks input lengths + * @param context The context to include in exception messages + * @param input the input to check + * @return input upon a successful check + * @throws ValidationException if the check fails. + */ + private String checkLength(String context, String input) throws ValidationException + { + return checkLength(context, input, input); + } + + /** + * checks input emptiness + * @param context The context to include in exception messages + * @param input the input to check + * @param orig A origional input to include in exception + * messages. This is not included if it is the same as + * input. + * @return input upon a successful check + * @throws ValidationException if the check fails. + */ + private String checkEmpty(String context, String input, String orig) throws ValidationException + { + if(!StringUtilities.isEmpty(input)) + return input; + if(allowNull) + return null; + throw new ValidationException( context + ": Input required.", "Input required: context=" + context + "), input=" + input + (NullSafe.equals(input,orig) ? "" : ", orig=" + orig), context ); + } + + /** + * checks input emptiness + * @param context The context to include in exception messages + * @param input the input to check + * @return input upon a successful check + * @throws ValidationException if the check fails. + */ + private String checkEmpty(String context, String input) throws ValidationException + { + return checkEmpty(context, input, input); + } + + /** + * {@inheritDoc} + */ + public String getValid( String context, String input ) throws ValidationException + { + String data = null; + + // check for empty/null + if(checkEmpty(context, input) == null) + return null; + + // check length + checkLength(context, input); + + // canonicalize + if (canonicalizeInput) { + data = encoder.canonicalize(input); + } else { + String message = String.format("Input validation excludes canonicalization. Context: %s Input: %s", context, input); + LOGGER.warning(Logger.SECURITY_AUDIT, message); data = input; - } - - // check whitelist patterns - checkWhitelist(context, data, input); - - // check blacklist patterns - checkBlacklist(context, data, input); - - // validation passed - return data; - } - - /** - * {@inheritDoc} - */ - @Override - public String sanitize( String context, String input ) { - return whitelist( input, EncoderConstants.CHAR_ALPHANUMERICS ); - } + } + + // check whitelist patterns + checkWhitelist(context, data, input); + + // check blacklist patterns + checkBlacklist(context, data, input); + + // validation passed + return data; + } + + /** + * {@inheritDoc} + */ + @Override + public String sanitize( String context, String input ) { + return whitelist( input, EncoderConstants.CHAR_ALPHANUMERICS ); + } } diff --git a/src/main/java/org/owasp/esapi/tags/BaseEncodeTag.java b/src/main/java/org/owasp/esapi/tags/BaseEncodeTag.java index c40a04fb4..e52b7402b 100644 --- a/src/main/java/org/owasp/esapi/tags/BaseEncodeTag.java +++ b/src/main/java/org/owasp/esapi/tags/BaseEncodeTag.java @@ -28,43 +28,43 @@ /** Abstract base class for tags that just encode their bodies with Encoder methods. */ public abstract class BaseEncodeTag extends BodyTagSupport { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - /** - * Encode tag's content. - * @param content The tag's content as a String - * @param enc Encoder provided as a convinence. - * @return content encoded by the subclass's implementation. - */ - protected abstract String encode(String content, Encoder enc) throws JspTagException; + /** + * Encode tag's content. + * @param content The tag's content as a String + * @param enc Encoder provided as a convinence. + * @return content encoded by the subclass's implementation. + */ + protected abstract String encode(String content, Encoder enc) throws JspTagException; - /** - * After tag body parsing handler. This provides the necessary - * plubming to allow subclasses to just concern themselves with - * encoding a single string. - * @return {@link javax.servlet.jsp.tagext.Tag#SKIP_BODY} - * @throws JspTagException if writing to the bodyContent's - * enclosing writer throws an IOException. - */ - public int doAfterBody() throws JspTagException - { - String content; - JspWriter out; + /** + * After tag body parsing handler. This provides the necessary + * plubming to allow subclasses to just concern themselves with + * encoding a single string. + * @return {@link javax.servlet.jsp.tagext.Tag#SKIP_BODY} + * @throws JspTagException if writing to the bodyContent's + * enclosing writer throws an IOException. + */ + public int doAfterBody() throws JspTagException + { + String content; + JspWriter out; - content = bodyContent.getString(); - out = bodyContent.getEnclosingWriter(); + content = bodyContent.getString(); + out = bodyContent.getEnclosingWriter(); - content = encode(content, ESAPI.encoder()); - try - { - out.print(content); - } - catch (IOException e) - { - throw new JspTagException("Error writing to body's enclosing JspWriter",e); - } + content = encode(content, ESAPI.encoder()); + try + { + out.print(content); + } + catch (IOException e) + { + throw new JspTagException("Error writing to body's enclosing JspWriter",e); + } - bodyContent.clearBody(); - return SKIP_BODY; - } + bodyContent.clearBody(); + return SKIP_BODY; + } } diff --git a/src/main/java/org/owasp/esapi/tags/ELEncodeFunctions.java b/src/main/java/org/owasp/esapi/tags/ELEncodeFunctions.java index 5b74e1e83..b8a2228f4 100644 --- a/src/main/java/org/owasp/esapi/tags/ELEncodeFunctions.java +++ b/src/main/java/org/owasp/esapi/tags/ELEncodeFunctions.java @@ -11,162 +11,162 @@ */ public class ELEncodeFunctions { - private static final String DEFAULT_ENCODING = "UTF-8"; - - /** - * Private constructor as this class shouldn't need to be - * instantiated. - */ - private ELEncodeFunctions() - { - } - - /** - * Base64 encode a string. UTF-8 is used to encode the string and no line wrapping is performed. - * @param str The string to encode. - * @return The base64 encoded String. - * @see Encoder#encodeForBase64(byte[],boolean) - * @throws UnsupportedEncodingException if UTF-8 is an unsupported character set. This should not happen as UTF-8 is required to be supported by the JVM spec. - */ - public static String encodeForBase64(String str) throws UnsupportedEncodingException - { - return encodeForBase64Charset(DEFAULT_ENCODING, str); - } - - /** - * Base64 encode a string with line wrapping. UTF-8 is used to encode the string and lines are wrapped at 64 characters.. - * @param str The string to encode. - * @return The base64 encoded String. - * @see Encoder#encodeForBase64(byte[],boolean) - * @throws UnsupportedEncodingException if UTF-8 is an unsupported character set. This should not happen as UTF-8 is required to be supported by the JVM spec. - */ - public static String encodeForBase64Wrap(String str) throws UnsupportedEncodingException - { - return encodeForBase64CharsetWrap(DEFAULT_ENCODING, str); - } - - /** - * Base64 encode a string after converting to bytes using the specified character set. No line wrapping is performed. - * @param charset The character set used to convert str to bytes. - * @param str The string to encode. - * @return The base64 encoded String. - * @see Encoder#encodeForBase64(byte[],boolean) - * @throws UnsupportedEncodingException if charset is an unsupported character set. - */ - public static String encodeForBase64Charset(String charset, String str) throws UnsupportedEncodingException - { - return ESAPI.encoder().encodeForBase64(str.getBytes(charset), false); - } - - /** - * Base64 encode a string after converting to bytes using the specified character set and wrapping lines. Lines are wrapped at 64 characters. - * @param charset The character set used to convert str to bytes. - * @param str The string to encode. - * @return The base64 encoded String. - * @see Encoder#encodeForBase64(byte[],boolean) - * @throws UnsupportedEncodingException if charset is an unsupported character set. - */ - public static String encodeForBase64CharsetWrap(String charset, String str) throws UnsupportedEncodingException - { - return ESAPI.encoder().encodeForBase64(str.getBytes(charset), true); - } - - /** - * Encode string for use in CSS. - * @param str The string to encode. - * @return str encoded for use in CSS. - * @see Encoder#encodeForCSS(String) - */ - public static String encodeForCSS(String str) - { - return ESAPI.encoder().encodeForCSS(str); - } - - /** - * Encode string for use in HTML. - * @param str The string to encode. - * @return str encoded for use in HTML. - * @see Encoder#encodeForHTML(String) - */ - public static String encodeForHTML(String str) - { - return ESAPI.encoder().encodeForHTML(str); - } - - /** - * Encode string for use in a HTML attribute. - * @param str The string to encode. - * @return str encoded for use in HTML attribute. - * @see Encoder#encodeForHTMLAttribute(String) - */ - public static String encodeForHTMLAttribute(String str) - { - return ESAPI.encoder().encodeForHTMLAttribute(str); - } - - /** - * Encode string for use in JavaScript. - * @param str The string to encode. - * @return str encoded for use in JavaScript. - * @see Encoder#encodeForJavaScript(String) - */ - public static String encodeForJavaScript(String str) - { - return ESAPI.encoder().encodeForJavaScript(str); - } - - /** - * Encode string for use in a URL. - * @param str The string to encode. - * @return str encoded for use in a URL. - * @see Encoder#encodeForURL(String) - */ - public static String encodeForURL(String str) throws EncodingException - { - return ESAPI.encoder().encodeForURL(str); - } - - /** - * Encode string for use in VBScript. - * @param str The string to encode. - * @return str encoded for use in VBScript. - * @see Encoder#encodeForVBScript(String) - */ - public static String encodeForVBScript(String str) - { - return ESAPI.encoder().encodeForVBScript(str); - } - - /** - * Encode string for use in XML. - * @param str The string to encode. - * @return str encoded for use in XML. - * @see Encoder#encodeForXML(String) - */ - public static String encodeForXML(String str) - { - return ESAPI.encoder().encodeForXML(str); - } - - /** - * Encode string for use in a XML attribute. - * @param str The string to encode. - * @return str encoded for use in XML attribute. - * @see Encoder#encodeForXMLAttribute(String) - */ - public static String encodeForXMLAttribute(String str) - { - return ESAPI.encoder().encodeForXMLAttribute(str); - } - - /** - * Encode string for use in XPath. - * @param str The string to encode. - * @return str encoded for use in XPath. - * @see Encoder#encodeForXPath(String) - */ - public static String encodeForXPath(String str) - { - return ESAPI.encoder().encodeForXPath(str); - } + private static final String DEFAULT_ENCODING = "UTF-8"; + + /** + * Private constructor as this class shouldn't need to be + * instantiated. + */ + private ELEncodeFunctions() + { + } + + /** + * Base64 encode a string. UTF-8 is used to encode the string and no line wrapping is performed. + * @param str The string to encode. + * @return The base64 encoded String. + * @see Encoder#encodeForBase64(byte[],boolean) + * @throws UnsupportedEncodingException if UTF-8 is an unsupported character set. This should not happen as UTF-8 is required to be supported by the JVM spec. + */ + public static String encodeForBase64(String str) throws UnsupportedEncodingException + { + return encodeForBase64Charset(DEFAULT_ENCODING, str); + } + + /** + * Base64 encode a string with line wrapping. UTF-8 is used to encode the string and lines are wrapped at 64 characters.. + * @param str The string to encode. + * @return The base64 encoded String. + * @see Encoder#encodeForBase64(byte[],boolean) + * @throws UnsupportedEncodingException if UTF-8 is an unsupported character set. This should not happen as UTF-8 is required to be supported by the JVM spec. + */ + public static String encodeForBase64Wrap(String str) throws UnsupportedEncodingException + { + return encodeForBase64CharsetWrap(DEFAULT_ENCODING, str); + } + + /** + * Base64 encode a string after converting to bytes using the specified character set. No line wrapping is performed. + * @param charset The character set used to convert str to bytes. + * @param str The string to encode. + * @return The base64 encoded String. + * @see Encoder#encodeForBase64(byte[],boolean) + * @throws UnsupportedEncodingException if charset is an unsupported character set. + */ + public static String encodeForBase64Charset(String charset, String str) throws UnsupportedEncodingException + { + return ESAPI.encoder().encodeForBase64(str.getBytes(charset), false); + } + + /** + * Base64 encode a string after converting to bytes using the specified character set and wrapping lines. Lines are wrapped at 64 characters. + * @param charset The character set used to convert str to bytes. + * @param str The string to encode. + * @return The base64 encoded String. + * @see Encoder#encodeForBase64(byte[],boolean) + * @throws UnsupportedEncodingException if charset is an unsupported character set. + */ + public static String encodeForBase64CharsetWrap(String charset, String str) throws UnsupportedEncodingException + { + return ESAPI.encoder().encodeForBase64(str.getBytes(charset), true); + } + + /** + * Encode string for use in CSS. + * @param str The string to encode. + * @return str encoded for use in CSS. + * @see Encoder#encodeForCSS(String) + */ + public static String encodeForCSS(String str) + { + return ESAPI.encoder().encodeForCSS(str); + } + + /** + * Encode string for use in HTML. + * @param str The string to encode. + * @return str encoded for use in HTML. + * @see Encoder#encodeForHTML(String) + */ + public static String encodeForHTML(String str) + { + return ESAPI.encoder().encodeForHTML(str); + } + + /** + * Encode string for use in a HTML attribute. + * @param str The string to encode. + * @return str encoded for use in HTML attribute. + * @see Encoder#encodeForHTMLAttribute(String) + */ + public static String encodeForHTMLAttribute(String str) + { + return ESAPI.encoder().encodeForHTMLAttribute(str); + } + + /** + * Encode string for use in JavaScript. + * @param str The string to encode. + * @return str encoded for use in JavaScript. + * @see Encoder#encodeForJavaScript(String) + */ + public static String encodeForJavaScript(String str) + { + return ESAPI.encoder().encodeForJavaScript(str); + } + + /** + * Encode string for use in a URL. + * @param str The string to encode. + * @return str encoded for use in a URL. + * @see Encoder#encodeForURL(String) + */ + public static String encodeForURL(String str) throws EncodingException + { + return ESAPI.encoder().encodeForURL(str); + } + + /** + * Encode string for use in VBScript. + * @param str The string to encode. + * @return str encoded for use in VBScript. + * @see Encoder#encodeForVBScript(String) + */ + public static String encodeForVBScript(String str) + { + return ESAPI.encoder().encodeForVBScript(str); + } + + /** + * Encode string for use in XML. + * @param str The string to encode. + * @return str encoded for use in XML. + * @see Encoder#encodeForXML(String) + */ + public static String encodeForXML(String str) + { + return ESAPI.encoder().encodeForXML(str); + } + + /** + * Encode string for use in a XML attribute. + * @param str The string to encode. + * @return str encoded for use in XML attribute. + * @see Encoder#encodeForXMLAttribute(String) + */ + public static String encodeForXMLAttribute(String str) + { + return ESAPI.encoder().encodeForXMLAttribute(str); + } + + /** + * Encode string for use in XPath. + * @param str The string to encode. + * @return str encoded for use in XPath. + * @see Encoder#encodeForXPath(String) + */ + public static String encodeForXPath(String str) + { + return ESAPI.encoder().encodeForXPath(str); + } } diff --git a/src/main/java/org/owasp/esapi/tags/EncodeForBase64Tag.java b/src/main/java/org/owasp/esapi/tags/EncodeForBase64Tag.java index dbde61af9..5551f2251 100644 --- a/src/main/java/org/owasp/esapi/tags/EncodeForBase64Tag.java +++ b/src/main/java/org/owasp/esapi/tags/EncodeForBase64Tag.java @@ -11,72 +11,72 @@ */ public class EncodeForBase64Tag extends BaseEncodeTag { - private static final long serialVersionUID = 3L; - /** @serial Flag determining line wrapping */ - private boolean wrap = false; - /** - * @serial Charset to use when converting content from a String - * to byte[]. - */ - private String encoding = "UTF-8"; + private static final long serialVersionUID = 3L; + /** @serial Flag determining line wrapping */ + private boolean wrap = false; + /** + * @serial Charset to use when converting content from a String + * to byte[]. + */ + private String encoding = "UTF-8"; - /** - * Encode tag's content using Base64. - * @param content The tag's content as a String - * @param enc Encoder used to call - * {@link Encoder#encodeForBase64(byte[], boolean)} - * @return content encoded in Base64 - */ - protected String encode(String content, Encoder enc) throws JspTagException - { - try - { - return enc.encodeForBase64(content.getBytes(encoding), wrap); - } - catch(UnsupportedEncodingException e) - { - throw new JspTagException("Unsupported encoding " + enc,e); - } - } + /** + * Encode tag's content using Base64. + * @param content The tag's content as a String + * @param enc Encoder used to call + * {@link Encoder#encodeForBase64(byte[], boolean)} + * @return content encoded in Base64 + */ + protected String encode(String content, Encoder enc) throws JspTagException + { + try + { + return enc.encodeForBase64(content.getBytes(encoding), wrap); + } + catch(UnsupportedEncodingException e) + { + throw new JspTagException("Unsupported encoding " + enc,e); + } + } - /** - * Set the encoding used to convert the content to bytes for - * encoding. This defaults to UTF-8 if not specified. - * @param encoding The encoding passed to {@link String#getBytes(String)}. - */ - public void setEncoding(String encoding) - { - this.encoding=encoding; - } + /** + * Set the encoding used to convert the content to bytes for + * encoding. This defaults to UTF-8 if not specified. + * @param encoding The encoding passed to {@link String#getBytes(String)}. + */ + public void setEncoding(String encoding) + { + this.encoding=encoding; + } - /** - * Get the encoding used to convert the content to bytes for - * encoding. - * @return encoding The encoding passed to - * {@link String#getBytes(String)}. - */ - public String getEncoding() - { - return encoding; - } + /** + * Get the encoding used to convert the content to bytes for + * encoding. + * @return encoding The encoding passed to + * {@link String#getBytes(String)}. + */ + public String getEncoding() + { + return encoding; + } - /** - * Set whether line wrapping at 64 characters is performed. This - * defaults to false. - * @param wrap flag determining wrapping. - */ - public void setWrap(boolean wrap) - { - this.wrap=wrap; - } + /** + * Set whether line wrapping at 64 characters is performed. This + * defaults to false. + * @param wrap flag determining wrapping. + */ + public void setWrap(boolean wrap) + { + this.wrap=wrap; + } - /** - * Get whether line wrapping at 64 characters is performed. This - * defaults to false. - * @return value of flag determining wrapping. - */ - public boolean getWrap() - { - return wrap; - } + /** + * Get whether line wrapping at 64 characters is performed. This + * defaults to false. + * @return value of flag determining wrapping. + */ + public boolean getWrap() + { + return wrap; + } } diff --git a/src/main/java/org/owasp/esapi/tags/EncodeForCSSTag.java b/src/main/java/org/owasp/esapi/tags/EncodeForCSSTag.java index c4bfebd8e..1def5ee07 100644 --- a/src/main/java/org/owasp/esapi/tags/EncodeForCSSTag.java +++ b/src/main/java/org/owasp/esapi/tags/EncodeForCSSTag.java @@ -7,17 +7,17 @@ */ public class EncodeForCSSTag extends BaseEncodeTag { - private static final long serialVersionUID = 3L; + private static final long serialVersionUID = 3L; - /** - * Encode tag's content for usage in CSS. - * @param content The tag's content as a String - * @param enc Encoder used to call - * {@link Encoder#encodeForCSS(String)} - * @return content encoded for usage in CSS - */ - protected String encode(String content, Encoder enc) - { - return enc.encodeForCSS(content); - } + /** + * Encode tag's content for usage in CSS. + * @param content The tag's content as a String + * @param enc Encoder used to call + * {@link Encoder#encodeForCSS(String)} + * @return content encoded for usage in CSS + */ + protected String encode(String content, Encoder enc) + { + return enc.encodeForCSS(content); + } } diff --git a/src/main/java/org/owasp/esapi/tags/EncodeForHTMLAttributeTag.java b/src/main/java/org/owasp/esapi/tags/EncodeForHTMLAttributeTag.java index ed48c971c..5e07d8c7f 100644 --- a/src/main/java/org/owasp/esapi/tags/EncodeForHTMLAttributeTag.java +++ b/src/main/java/org/owasp/esapi/tags/EncodeForHTMLAttributeTag.java @@ -23,17 +23,17 @@ */ public class EncodeForHTMLAttributeTag extends BaseEncodeTag { - private static final long serialVersionUID = 3L; + private static final long serialVersionUID = 3L; - /** - * Encode tag's content for usage as a HTML attribute. - * @param content The tag's content as a String - * @param enc Encoder used to call - * {@link Encoder#encodeForHTMLAttribute(String)} - * @return content encoded for usage as a HTML attribute - */ - protected String encode(String content, Encoder enc) - { - return enc.encodeForHTMLAttribute(content); - } + /** + * Encode tag's content for usage as a HTML attribute. + * @param content The tag's content as a String + * @param enc Encoder used to call + * {@link Encoder#encodeForHTMLAttribute(String)} + * @return content encoded for usage as a HTML attribute + */ + protected String encode(String content, Encoder enc) + { + return enc.encodeForHTMLAttribute(content); + } } diff --git a/src/main/java/org/owasp/esapi/tags/EncodeForHTMLTag.java b/src/main/java/org/owasp/esapi/tags/EncodeForHTMLTag.java index ee7916f75..3cd317557 100644 --- a/src/main/java/org/owasp/esapi/tags/EncodeForHTMLTag.java +++ b/src/main/java/org/owasp/esapi/tags/EncodeForHTMLTag.java @@ -23,17 +23,17 @@ */ public class EncodeForHTMLTag extends BaseEncodeTag { - private static final long serialVersionUID = 3L; + private static final long serialVersionUID = 3L; - /** - * Encode tag's content for usage in HTML. - * @param content The tag's content as a String - * @param enc Encoder used to call - * {@link Encoder#encodeForHTML(String)} - * @return content encoded for usage in HTML - */ - protected String encode(String content, Encoder enc) - { - return enc.encodeForHTML(content); - } + /** + * Encode tag's content for usage in HTML. + * @param content The tag's content as a String + * @param enc Encoder used to call + * {@link Encoder#encodeForHTML(String)} + * @return content encoded for usage in HTML + */ + protected String encode(String content, Encoder enc) + { + return enc.encodeForHTML(content); + } } diff --git a/src/main/java/org/owasp/esapi/tags/EncodeForJavaScriptTag.java b/src/main/java/org/owasp/esapi/tags/EncodeForJavaScriptTag.java index 8069401b8..fe4d68eb9 100644 --- a/src/main/java/org/owasp/esapi/tags/EncodeForJavaScriptTag.java +++ b/src/main/java/org/owasp/esapi/tags/EncodeForJavaScriptTag.java @@ -7,17 +7,17 @@ */ public class EncodeForJavaScriptTag extends BaseEncodeTag { - private static final long serialVersionUID = 3L; + private static final long serialVersionUID = 3L; - /** - * Encode tag's content for usage in JavaScript - * @param content The tag's content as a String - * @param enc Encoder used to call - * {@link Encoder#encodeForJavaScript(String)} - * @return content encoded for usage in JavaScript - */ - protected String encode(String content, Encoder enc) - { - return enc.encodeForJavaScript(content); - } + /** + * Encode tag's content for usage in JavaScript + * @param content The tag's content as a String + * @param enc Encoder used to call + * {@link Encoder#encodeForJavaScript(String)} + * @return content encoded for usage in JavaScript + */ + protected String encode(String content, Encoder enc) + { + return enc.encodeForJavaScript(content); + } } diff --git a/src/main/java/org/owasp/esapi/tags/EncodeForURLTag.java b/src/main/java/org/owasp/esapi/tags/EncodeForURLTag.java index d159676e1..28b03af7e 100644 --- a/src/main/java/org/owasp/esapi/tags/EncodeForURLTag.java +++ b/src/main/java/org/owasp/esapi/tags/EncodeForURLTag.java @@ -10,25 +10,25 @@ */ public class EncodeForURLTag extends BaseEncodeTag { - private static final long serialVersionUID = 3L; + private static final long serialVersionUID = 3L; - /** - * Encode tag's content for usage in a URL. - * @param content The tag's content as a String - * @param enc Encoder used to call - * {@link Encoder#encodeForURL(String)} - * @return content encoded for usage in a URL - * @throws EncodingException if {@link Encoder#encodeForURL(String)} does. - */ - protected String encode(String content, Encoder enc) throws JspTagException - { - try - { - return enc.encodeForURL(content); - } - catch(EncodingException e) - { - throw new JspTagException("Unable to encode to URL encoding", e); - } - } + /** + * Encode tag's content for usage in a URL. + * @param content The tag's content as a String + * @param enc Encoder used to call + * {@link Encoder#encodeForURL(String)} + * @return content encoded for usage in a URL + * @throws EncodingException if {@link Encoder#encodeForURL(String)} does. + */ + protected String encode(String content, Encoder enc) throws JspTagException + { + try + { + return enc.encodeForURL(content); + } + catch(EncodingException e) + { + throw new JspTagException("Unable to encode to URL encoding", e); + } + } } diff --git a/src/main/java/org/owasp/esapi/tags/EncodeForVBScriptTag.java b/src/main/java/org/owasp/esapi/tags/EncodeForVBScriptTag.java index d090fad29..43ddee272 100644 --- a/src/main/java/org/owasp/esapi/tags/EncodeForVBScriptTag.java +++ b/src/main/java/org/owasp/esapi/tags/EncodeForVBScriptTag.java @@ -23,17 +23,17 @@ */ public class EncodeForVBScriptTag extends BaseEncodeTag { - private static final long serialVersionUID = 3L; + private static final long serialVersionUID = 3L; - /** - * Encode tag's content for usage in VBScript. - * @param content The tag's content as a String - * @param enc Encoder used to call - * {@link Encoder#encodeForVBScript(String)} - * @return content encoded for usage in VBScript - */ - protected String encode(String content, Encoder enc) - { - return enc.encodeForVBScript(content); - } + /** + * Encode tag's content for usage in VBScript. + * @param content The tag's content as a String + * @param enc Encoder used to call + * {@link Encoder#encodeForVBScript(String)} + * @return content encoded for usage in VBScript + */ + protected String encode(String content, Encoder enc) + { + return enc.encodeForVBScript(content); + } } diff --git a/src/main/java/org/owasp/esapi/tags/EncodeForXMLAttributeTag.java b/src/main/java/org/owasp/esapi/tags/EncodeForXMLAttributeTag.java index c14746719..4ad11e87a 100644 --- a/src/main/java/org/owasp/esapi/tags/EncodeForXMLAttributeTag.java +++ b/src/main/java/org/owasp/esapi/tags/EncodeForXMLAttributeTag.java @@ -7,17 +7,17 @@ */ public class EncodeForXMLAttributeTag extends BaseEncodeTag { - private static final long serialVersionUID = 3L; + private static final long serialVersionUID = 3L; - /** - * Encode tag's content for usage as a XML attribute. - * @param content The tag's content as a String - * @param enc Encoder used to call - * {@link Encoder#encodeForXMLAttribute(String)} - * @return content encoded for usage as a XML attribute - */ - protected String encode(String content, Encoder enc) - { - return enc.encodeForXMLAttribute(content); - } + /** + * Encode tag's content for usage as a XML attribute. + * @param content The tag's content as a String + * @param enc Encoder used to call + * {@link Encoder#encodeForXMLAttribute(String)} + * @return content encoded for usage as a XML attribute + */ + protected String encode(String content, Encoder enc) + { + return enc.encodeForXMLAttribute(content); + } } diff --git a/src/main/java/org/owasp/esapi/tags/EncodeForXMLTag.java b/src/main/java/org/owasp/esapi/tags/EncodeForXMLTag.java index f86cfe1ab..320b0484a 100644 --- a/src/main/java/org/owasp/esapi/tags/EncodeForXMLTag.java +++ b/src/main/java/org/owasp/esapi/tags/EncodeForXMLTag.java @@ -7,17 +7,17 @@ */ public class EncodeForXMLTag extends BaseEncodeTag { - private static final long serialVersionUID = 3L; + private static final long serialVersionUID = 3L; - /** - * Encode tag's content for usage in XML. - * @param content The tag's content as a String - * @param enc Encoder used to call - * {@link Encoder#encodeForXML(String)} - * @return content encoded for usage in XML - */ - protected String encode(String content, Encoder enc) - { - return enc.encodeForXML(content); - } + /** + * Encode tag's content for usage in XML. + * @param content The tag's content as a String + * @param enc Encoder used to call + * {@link Encoder#encodeForXML(String)} + * @return content encoded for usage in XML + */ + protected String encode(String content, Encoder enc) + { + return enc.encodeForXML(content); + } } diff --git a/src/main/java/org/owasp/esapi/tags/EncodeForXPathTag.java b/src/main/java/org/owasp/esapi/tags/EncodeForXPathTag.java index 064b19149..1ff953880 100644 --- a/src/main/java/org/owasp/esapi/tags/EncodeForXPathTag.java +++ b/src/main/java/org/owasp/esapi/tags/EncodeForXPathTag.java @@ -7,17 +7,17 @@ */ public class EncodeForXPathTag extends BaseEncodeTag { - private static final long serialVersionUID = 3L; + private static final long serialVersionUID = 3L; - /** - * Encode tag's content for usage in XPath. - * @param content The tag's content as a String - * @param enc Encoder used to call - * {@link Encoder#encodeForXPath(String)} - * @return content encoded for usage in XPath - */ - protected String encode(String content, Encoder enc) - { - return enc.encodeForXPath(content); - } + /** + * Encode tag's content for usage in XPath. + * @param content The tag's content as a String + * @param enc Encoder used to call + * {@link Encoder#encodeForXPath(String)} + * @return content encoded for usage in XPath + */ + protected String encode(String content, Encoder enc) + { + return enc.encodeForXPath(content); + } } diff --git a/src/main/java/org/owasp/esapi/util/CollectionsUtil.java b/src/main/java/org/owasp/esapi/util/CollectionsUtil.java index 3cb2f2831..73f919766 100644 --- a/src/main/java/org/owasp/esapi/util/CollectionsUtil.java +++ b/src/main/java/org/owasp/esapi/util/CollectionsUtil.java @@ -19,97 +19,97 @@ */ public class CollectionsUtil { - private static final char[] EMPTY_CHAR_ARRAY = new char[0]; + private static final char[] EMPTY_CHAR_ARRAY = new char[0]; - /** - * Converts an array of chars to a Set of Characters. - * @param array the contents of the new Set - * @return a Set containing the elements in the array - */ - public static Set arrayToSet(char...array) - { - Set toReturn; + /** + * Converts an array of chars to a Set of Characters. + * @param array the contents of the new Set + * @return a Set containing the elements in the array + */ + public static Set arrayToSet(char...array) + { + Set toReturn; - if(array == null) - return new HashSet(); - toReturn = new HashSet(array.length); - for (char c : array) { - toReturn.add(c); - } - return toReturn; - } + if(array == null) + return new HashSet(); + toReturn = new HashSet(array.length); + for (char c : array) { + toReturn.add(c); + } + return toReturn; + } - /** - * Convert a char array to a unmodifiable Set. - * @param array the contents of the new Set - * @return a unmodifiable Set containing the elements in the - * array. - */ - public static Set arrayToUnmodifiableSet(char...array) - { - if(array == null) - return Collections.emptySet(); - if(array.length == 1) - return Collections.singleton(array[0]); - return Collections.unmodifiableSet(arrayToSet(array)); - } + /** + * Convert a char array to a unmodifiable Set. + * @param array the contents of the new Set + * @return a unmodifiable Set containing the elements in the + * array. + */ + public static Set arrayToUnmodifiableSet(char...array) + { + if(array == null) + return Collections.emptySet(); + if(array.length == 1) + return Collections.singleton(array[0]); + return Collections.unmodifiableSet(arrayToSet(array)); + } - /** - * Convert a String to a char array - * @param str The string to convert - * @return character array containing the characters in str. An - * empty array is returned if str is null. - */ - public static char[] strToChars(String str) - { - int len; - char[] ret; + /** + * Convert a String to a char array + * @param str The string to convert + * @return character array containing the characters in str. An + * empty array is returned if str is null. + */ + public static char[] strToChars(String str) + { + int len; + char[] ret; - if(str == null) - return EMPTY_CHAR_ARRAY; - len = str.length(); - ret = new char[len]; - str.getChars(0,len,ret,0); - return ret; - } + if(str == null) + return EMPTY_CHAR_ARRAY; + len = str.length(); + ret = new char[len]; + str.getChars(0,len,ret,0); + return ret; + } - /** - * Convert a String to a set of characters. - * @param str The string to convert - * @return A set containing the characters in str. A empty set - * is returned if str is null. - */ - public static Set strToSet(String str) - { - Set set; + /** + * Convert a String to a set of characters. + * @param str The string to convert + * @return A set containing the characters in str. A empty set + * is returned if str is null. + */ + public static Set strToSet(String str) + { + Set set; - if(str == null) - return new HashSet(); - set = new HashSet(str.length()); - for(int i=0;i(); + set = new HashSet(str.length()); + for(int i=0;i strToUnmodifiableSet(String str) - { - if(str == null) - return Collections.emptySet(); - if(str.length() == 1) - return Collections.singleton(str.charAt(0)); - return Collections.unmodifiableSet(strToSet(str)); - } + /** + * Convert a String to a unmodifiable set of characters. + * @param str The string to convert + * @return A set containing the characters in str. A empty set + * is returned if str is null. + */ + public static Set strToUnmodifiableSet(String str) + { + if(str == null) + return Collections.emptySet(); + if(str.length() == 1) + return Collections.singleton(str.charAt(0)); + return Collections.unmodifiableSet(strToSet(str)); + } - /** - * Private constructor to prevent instantiation. - */ - private CollectionsUtil() - { - } + /** + * Private constructor to prevent instantiation. + */ + private CollectionsUtil() + { + } } diff --git a/src/main/java/org/owasp/esapi/util/DefaultMessageUtil.java b/src/main/java/org/owasp/esapi/util/DefaultMessageUtil.java index 1cce29627..6d1a45217 100644 --- a/src/main/java/org/owasp/esapi/util/DefaultMessageUtil.java +++ b/src/main/java/org/owasp/esapi/util/DefaultMessageUtil.java @@ -33,7 +33,7 @@ public class DefaultMessageUtil { private ResourceBundle messages = null; public void initialize() { - try { + try { messages = ResourceBundle.getBundle("ESAPI", ESAPI.authenticator().getCurrentUser().getLocale()); } catch (Exception e) { messages = ResourceBundle.getBundle("ESAPI", new Locale(DEFAULT_LOCALE_LANG,DEFAULT_LOCALE_LOC)); @@ -41,9 +41,9 @@ public void initialize() { } - public String getMessage(String msgKey, Object[] arguments) { - - initialize(); - return MessageFormat.format( messages.getString(msgKey), arguments ); - } + public String getMessage(String msgKey, Object[] arguments) { + + initialize(); + return MessageFormat.format( messages.getString(msgKey), arguments ); + } } \ No newline at end of file diff --git a/src/main/java/org/owasp/esapi/util/NullSafe.java b/src/main/java/org/owasp/esapi/util/NullSafe.java index 062c0fa67..a0bee5f55 100644 --- a/src/main/java/org/owasp/esapi/util/NullSafe.java +++ b/src/main/java/org/owasp/esapi/util/NullSafe.java @@ -2,51 +2,51 @@ public class NullSafe { - /** - * Class should not be instantiated. - */ - private NullSafe() - { - } + /** + * Class should not be instantiated. + */ + private NullSafe() + { + } - /** - * {@link Object#equals(Object)} that safely handles nulls. - * @param a First object - * @param b Second object - * @return true if a == b or a.equals(b). false otherwise. - */ - public static boolean equals(Object a, Object b) - { - if(a==b) // short cut same object - return true; - if(a == null) - return (b == null); - if(b == null) - return false; - return a.equals(b); - } + /** + * {@link Object#equals(Object)} that safely handles nulls. + * @param a First object + * @param b Second object + * @return true if a == b or a.equals(b). false otherwise. + */ + public static boolean equals(Object a, Object b) + { + if(a==b) // short cut same object + return true; + if(a == null) + return (b == null); + if(b == null) + return false; + return a.equals(b); + } - /** - * {@link Object#hashCode()} of an object. - * @param o Object to get a hashCode for. - * @return 0 if o is null. Otherwise o.hashCode(). - */ - public static int hashCode(Object o) - { - if(o == null) - return 0; - return o.hashCode(); - } + /** + * {@link Object#hashCode()} of an object. + * @param o Object to get a hashCode for. + * @return 0 if o is null. Otherwise o.hashCode(). + */ + public static int hashCode(Object o) + { + if(o == null) + return 0; + return o.hashCode(); + } - /** - * {@link Object#toString()} of an object. - * @param o Object to get a String for. - * @return "(null)" o is null. Otherwise o.toString(). - */ - public static String toString(Object o) - { - if(o == null) - return "(null)"; - return o.toString(); - } + /** + * {@link Object#toString()} of an object. + * @param o Object to get a String for. + * @return "(null)" o is null. Otherwise o.toString(). + */ + public static String toString(Object o) + { + if(o == null) + return "(null)"; + return o.toString(); + } } diff --git a/src/main/java/org/owasp/esapi/util/ObjFactory.java b/src/main/java/org/owasp/esapi/util/ObjFactory.java index 7853ef593..beca4391e 100644 --- a/src/main/java/org/owasp/esapi/util/ObjFactory.java +++ b/src/main/java/org/owasp/esapi/util/ObjFactory.java @@ -25,17 +25,17 @@ *

    * Typical use is something like: *

    - * 		import com.example.interfaces.DrinkingEstablishment;
    - * 		import com.example.interfaces.Beer;
    - * 		...
    - * 		// Typically these would be populated from some Java properties file
    - * 		String barName = "com.example.foo.Bar";
    - * 		String beerBrand = "com.example.brewery.Guinness";
    - * 		...
    - * 		DrinkingEstablishment bar = ObjFactory.make(barName, "DrinkingEstablishment");
    - * 		Beer beer = ObjFactory.make(beerBrand, "Beer");
    - *		bar.drink(beer);	// Drink a Guinness beer at the foo Bar. :)
    - *		...
    + *         import com.example.interfaces.DrinkingEstablishment;
    + *         import com.example.interfaces.Beer;
    + *         ...
    + *         // Typically these would be populated from some Java properties file
    + *         String barName = "com.example.foo.Bar";
    + *         String beerBrand = "com.example.brewery.Guinness";
    + *         ...
    + *         DrinkingEstablishment bar = ObjFactory.make(barName, "DrinkingEstablishment");
    + *         Beer beer = ObjFactory.make(beerBrand, "Beer");
    + *        bar.drink(beer);    // Drink a Guinness beer at the foo Bar. :)
    + *        ...
      * 
    *

    * Copyright (c) 2009 - The OWASP Foundation @@ -46,44 +46,44 @@ public class ObjFactory { private static final int CACHE_INITIAL_CAPACITY = 32; - private static final float CACHE_LOAD_FACTOR = 0.75F; - private static final ConcurrentHashMap> CLASSES_CACHE = new ConcurrentHashMap<>(CACHE_INITIAL_CAPACITY, CACHE_LOAD_FACTOR); - private static final ConcurrentHashMap METHODS_CACHE = new ConcurrentHashMap<>(CACHE_INITIAL_CAPACITY, CACHE_LOAD_FACTOR); + private static final float CACHE_LOAD_FACTOR = 0.75F; + private static final ConcurrentHashMap> CLASSES_CACHE = new ConcurrentHashMap<>(CACHE_INITIAL_CAPACITY, CACHE_LOAD_FACTOR); + private static final ConcurrentHashMap METHODS_CACHE = new ConcurrentHashMap<>(CACHE_INITIAL_CAPACITY, CACHE_LOAD_FACTOR); private static boolean cacheEnabled = true; - /** - * Create an object based on the className parameter. - * - * @param className The name of the class to construct. Should be a fully qualified name and - * generally the same as type T - * @param typeName A type name used in error messages / exceptions. - * @return An object of type className, which is cast to type T. - * @throws ConfigurationException thrown if class name not found in class path, or does not - * have a public, no-argument constructor, or is not a concrete class, or if it is - * not a sub-type of T (or T itself). Usually this is - * caused by a misconfiguration of the class names specified in the ESAPI.properties - * file. Also thrown if the CTOR of the specified className throws - * an Exception of some type. - */ - @SuppressWarnings({ "unchecked" }) // Added because of Eclipse warnings, but ClassCastException IS caught. - public static T make(String className, String typeName) throws ConfigurationException { - Object obj = null; - String errMsg = null; - try { - if (null == className || "".equals(className) ) { - throw new IllegalArgumentException("Classname cannot be null or empty."); - } - if (null == typeName || "".equals(typeName) ) { - // No big deal...just use "[unknown?]" for this as it's only for an err msg. - typeName = "[unknown?]"; // CHECKME: Any better suggestions? - } - - Class theClass = loadClassByStringName(className); - - try { - Method singleton = findSingletonCreateMethod(className, theClass); - - obj = singleton.invoke( null ); + /** + * Create an object based on the className parameter. + * + * @param className The name of the class to construct. Should be a fully qualified name and + * generally the same as type T + * @param typeName A type name used in error messages / exceptions. + * @return An object of type className, which is cast to type T. + * @throws ConfigurationException thrown if class name not found in class path, or does not + * have a public, no-argument constructor, or is not a concrete class, or if it is + * not a sub-type of T (or T itself). Usually this is + * caused by a misconfiguration of the class names specified in the ESAPI.properties + * file. Also thrown if the CTOR of the specified className throws + * an Exception of some type. + */ + @SuppressWarnings({ "unchecked" }) // Added because of Eclipse warnings, but ClassCastException IS caught. + public static T make(String className, String typeName) throws ConfigurationException { + Object obj = null; + String errMsg = null; + try { + if (null == className || "".equals(className) ) { + throw new IllegalArgumentException("Classname cannot be null or empty."); + } + if (null == typeName || "".equals(typeName) ) { + // No big deal...just use "[unknown?]" for this as it's only for an err msg. + typeName = "[unknown?]"; // CHECKME: Any better suggestions? + } + + Class theClass = loadClassByStringName(className); + + try { + Method singleton = findSingletonCreateMethod(className, theClass); + + obj = singleton.invoke( null ); } catch (NoSuchMethodException e) { // This is a no-error exception, if this is caught we will continue on assuming the implementation was // not meant to be used as a singleton. @@ -96,40 +96,40 @@ public static T make(String className, String typeName) throws Configuration "of the class [" + className + "]", e ); } - return (T)obj; // Eclipse warning here if @SupressWarnings omitted. + return (T)obj; // Eclipse warning here if @SupressWarnings omitted. // Issue 66 - Removed System.out calls as we are throwing an exception in each of these cases // anyhow. - } catch( IllegalArgumentException ex ) { - errMsg = ex.toString() + " " + typeName + " type name cannot be null or empty."; - throw new ConfigurationException(errMsg, ex); - }catch ( ClassNotFoundException ex ) { - errMsg = ex.toString() + " " + typeName + " class (" + className + ") must be in class path."; - throw new ConfigurationException(errMsg, ex); - } catch( InstantiationException ex ) { - errMsg = ex.toString() + " " + typeName + " class (" + className + ") must be concrete."; - throw new ConfigurationException(errMsg, ex); - } catch( IllegalAccessException ex ) { - errMsg = ex.toString() + " " + typeName + " class (" + className + ") must have a public, no-arg constructor."; - throw new ConfigurationException(errMsg, ex); - } catch( ClassCastException ex ) { - errMsg = ex.toString() + " " + typeName + " class (" + className + ") must be a subtype of T in ObjFactory"; - throw new ConfigurationException(errMsg, ex); - } catch( Exception ex ) { - // Because we are using reflection, we want to catch any checked or unchecked Exceptions and - // re-throw them in a way we can handle them. Because using reflection to construct the object, - // we can't have the compiler notify us of uncaught exceptions. For example, JavaEncryptor() - // CTOR can throw [well, now it can] an EncryptionException if something goes wrong. That case - // is taken care of here. - // - // CHECKME: Should we first catch RuntimeExceptions so we just let unchecked Exceptions go through - // unaltered??? - // - errMsg = ex.toString() + " " + typeName + " class (" + className + ") CTOR threw exception."; - throw new ConfigurationException(errMsg, ex); - } - // DISCUSS: Should we also catch ExceptionInInitializerError here? See Google Issue #61 comments. - } + } catch( IllegalArgumentException ex ) { + errMsg = ex.toString() + " " + typeName + " type name cannot be null or empty."; + throw new ConfigurationException(errMsg, ex); + }catch ( ClassNotFoundException ex ) { + errMsg = ex.toString() + " " + typeName + " class (" + className + ") must be in class path."; + throw new ConfigurationException(errMsg, ex); + } catch( InstantiationException ex ) { + errMsg = ex.toString() + " " + typeName + " class (" + className + ") must be concrete."; + throw new ConfigurationException(errMsg, ex); + } catch( IllegalAccessException ex ) { + errMsg = ex.toString() + " " + typeName + " class (" + className + ") must have a public, no-arg constructor."; + throw new ConfigurationException(errMsg, ex); + } catch( ClassCastException ex ) { + errMsg = ex.toString() + " " + typeName + " class (" + className + ") must be a subtype of T in ObjFactory"; + throw new ConfigurationException(errMsg, ex); + } catch( Exception ex ) { + // Because we are using reflection, we want to catch any checked or unchecked Exceptions and + // re-throw them in a way we can handle them. Because using reflection to construct the object, + // we can't have the compiler notify us of uncaught exceptions. For example, JavaEncryptor() + // CTOR can throw [well, now it can] an EncryptionException if something goes wrong. That case + // is taken care of here. + // + // CHECKME: Should we first catch RuntimeExceptions so we just let unchecked Exceptions go through + // unaltered??? + // + errMsg = ex.toString() + " " + typeName + " class (" + className + ") CTOR threw exception."; + throw new ConfigurationException(errMsg, ex); + } + // DISCUSS: Should we also catch ExceptionInInitializerError here? See Google Issue #61 comments. + } /** * Control whether cache for classes and method names should be enabled or disabled. Initial state is enabled. @@ -143,32 +143,32 @@ public static void setCache(boolean enable) { cacheEnabled = enable; } - /** - * Load the class in cache, or load by the classloader and cache it - * - * @param className The name of the class to construct. Should be a fully qualified name - * @return The target class - * @throws ClassNotFoundException Failed to load class by the className - */ - private static Class loadClassByStringName(String className) throws ClassNotFoundException { - Class clazz; - if (cacheEnabled && CLASSES_CACHE.containsKey(className)) { - clazz = CLASSES_CACHE.get(className); - } else { - clazz = Class.forName(className); - if ( cacheEnabled ) CLASSES_CACHE.putIfAbsent(className, clazz); - } - return clazz; - } - - /** - * Find the method to create a singleton object - * - * @param className The name of the class to construct. Should be a fully qualified name - * @param theClass The class loaded in prior - * @return The method to create a singleton object - * @throws NoSuchMethodException Failed to find the target method - */ + /** + * Load the class in cache, or load by the classloader and cache it + * + * @param className The name of the class to construct. Should be a fully qualified name + * @return The target class + * @throws ClassNotFoundException Failed to load class by the className + */ + private static Class loadClassByStringName(String className) throws ClassNotFoundException { + Class clazz; + if (cacheEnabled && CLASSES_CACHE.containsKey(className)) { + clazz = CLASSES_CACHE.get(className); + } else { + clazz = Class.forName(className); + if ( cacheEnabled ) CLASSES_CACHE.putIfAbsent(className, clazz); + } + return clazz; + } + + /** + * Find the method to create a singleton object + * + * @param className The name of the class to construct. Should be a fully qualified name + * @param theClass The class loaded in prior + * @return The method to create a singleton object + * @throws NoSuchMethodException Failed to find the target method + */ private static Method findSingletonCreateMethod(String className, Class theClass) throws NoSuchMethodException { MethodWrappedInfo singleton = loadMethodByStringName(className,theClass); @@ -180,13 +180,13 @@ private static Method findSingletonCreateMethod(String className, Class theCl return singleton.getMethod(); } - /** - * - * @param className The name of the class to construct. Should be a fully qualified name - * @param theClass The class loaded in prior - * @return Wrapped data, contains the method object and the method is static method or not - * @throws NoSuchMethodException Failed to find the target method - */ + /** + * + * @param className The name of the class to construct. Should be a fully qualified name + * @param theClass The class loaded in prior + * @return Wrapped data, contains the method object and the method is static method or not + * @throws NoSuchMethodException Failed to find the target method + */ private static MethodWrappedInfo loadMethodByStringName(String className, Class theClass) throws NoSuchMethodException { String methodName = className + "getInstance"; MethodWrappedInfo methodInfo; @@ -204,33 +204,33 @@ private static MethodWrappedInfo loadMethodByStringName(String className, Class< } /** - * Not instantiable - */ - private ObjFactory() { } + * Not instantiable + */ + private ObjFactory() { } - /** - * Wrapped data, contains the method object and the method is static method or not.
    - * The goal to store the boolean value in field staticMethod is reduce the check times: check once, use many times.
    + /** + * Wrapped data, contains the method object and the method is static method or not.
    + * The goal to store the boolean value in field staticMethod is reduce the check times: check once, use many times.
    * The goal to store the exception in field nonStaticException is reduce the cost of new Exception(): create once, use many times. - */ - private static class MethodWrappedInfo { - private Method method; - private boolean staticMethod; - private ConfigurationException nonStaticEx; - - MethodWrappedInfo(Method method, boolean staticMethod, ConfigurationException nonStaticEx) { - this.method = method; - this.staticMethod = staticMethod; - this.nonStaticEx = nonStaticEx; - } - - Method getMethod() { - return method; - } - - boolean isStaticMethod() { - return staticMethod; - } + */ + private static class MethodWrappedInfo { + private Method method; + private boolean staticMethod; + private ConfigurationException nonStaticEx; + + MethodWrappedInfo(Method method, boolean staticMethod, ConfigurationException nonStaticEx) { + this.method = method; + this.staticMethod = staticMethod; + this.nonStaticEx = nonStaticEx; + } + + Method getMethod() { + return method; + } + + boolean isStaticMethod() { + return staticMethod; + } ConfigurationException getNonStaticEx() { return nonStaticEx; diff --git a/src/main/java/org/owasp/esapi/waf/ConfigurationException.java b/src/main/java/org/owasp/esapi/waf/ConfigurationException.java index 644678e5e..9dd0ef639 100644 --- a/src/main/java/org/owasp/esapi/waf/ConfigurationException.java +++ b/src/main/java/org/owasp/esapi/waf/ConfigurationException.java @@ -28,15 +28,15 @@ */ public class ConfigurationException extends EnterpriseSecurityException { - protected static final long serialVersionUID = 1L; + protected static final long serialVersionUID = 1L; - public ConfigurationException(String userMsg, String logMsg) { - super(userMsg,logMsg); - } + public ConfigurationException(String userMsg, String logMsg) { + super(userMsg,logMsg); + } - public ConfigurationException(String userMsg, String logMsg, - Throwable t) { - super(userMsg,logMsg,t); - } + public ConfigurationException(String userMsg, String logMsg, + Throwable t) { + super(userMsg,logMsg,t); + } } diff --git a/src/main/java/org/owasp/esapi/waf/ESAPIWebApplicationFirewallFilter.java b/src/main/java/org/owasp/esapi/waf/ESAPIWebApplicationFirewallFilter.java index 82bd7e079..3bf56cab4 100644 --- a/src/main/java/org/owasp/esapi/waf/ESAPIWebApplicationFirewallFilter.java +++ b/src/main/java/org/owasp/esapi/waf/ESAPIWebApplicationFirewallFilter.java @@ -60,448 +60,448 @@ */ public class ESAPIWebApplicationFirewallFilter implements Filter { - private AppGuardianConfiguration appGuardConfig; - - private static final String CONFIGURATION_FILE_PARAM = "configuration"; - private static final String LOGGING_FILE_PARAM = "log_settings"; - private static final String POLLING_TIME_PARAM = "polling_time"; - - private static final int DEFAULT_POLLING_TIME = 30000; - - private String configurationFilename = null; - - private long pollingTime; - - private long lastConfigReadTime; - - // private static final String FAUX_SESSION_COOKIE = "FAUXSC"; - // private static final String SESSION_COOKIE_CANARY = - // "org.owasp.esapi.waf.canary"; - - private FilterConfig fc; - - private final Logger logger = ESAPI.getLogger(ESAPIWebApplicationFirewallFilter.class); - - /** - * This function is used in testing to dynamically alter the configuration. - * - * @param policyFilePath - * The path to the policy file - * @param webRootDir - * The root directory of the web application. - * @throws FileNotFoundException - * if the policy file cannot be located - */ - public void setConfiguration(String policyFilePath, String webRootDir) throws FileNotFoundException { - - FileInputStream inputStream = null; - - try { - inputStream = new FileInputStream(new File(policyFilePath)); - appGuardConfig = ConfigurationParser.readConfigurationFile(inputStream, webRootDir); - lastConfigReadTime = System.currentTimeMillis(); - configurationFilename = policyFilePath; - } catch (ConfigurationException e) { - // TODO: It would be ideal if this method through the - // ConfigurationException rather than catching it and - // writing the error to the console. - e.printStackTrace(); - } finally { - if (inputStream != null) { - try { - inputStream.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - } - - public AppGuardianConfiguration getConfiguration() { - return appGuardConfig; - } - - /** - * - * This function is invoked at application startup and when the - * configuration file polling period has elapsed and a change in the - * configuration file has been detected. - * - * It's main purpose is to read the configuration file and establish the - * configuration object model for use at runtime during the - * doFilter() method. - */ - public void init(FilterConfig fc) throws ServletException { - - /* - * This variable is saved so that we can retrieve it later to re-invoke - * this function. - */ - this.fc = fc; - - logger.debug(Logger.EVENT_SUCCESS, ">> Initializing WAF"); - /* - * Pull logging file. - */ - - // Demoted scope to a local since this is the only place it is - // referenced - String logSettingsFilename = fc.getInitParameter(LOGGING_FILE_PARAM); - - String realLogSettingsFilename = fc.getServletContext().getRealPath(logSettingsFilename); - - if (realLogSettingsFilename == null || (!new File(realLogSettingsFilename).exists())) { - throw new ServletException( - "[ESAPI WAF] Could not find log file at resolved path: " + realLogSettingsFilename); - } - - /* - * Pull main configuration file. - */ - - configurationFilename = fc.getInitParameter(CONFIGURATION_FILE_PARAM); - - configurationFilename = fc.getServletContext().getRealPath(configurationFilename); - - if (configurationFilename == null || !new File(configurationFilename).exists()) { - throw new ServletException( - "[ESAPI WAF] Could not find configuration file at resolved path: " + configurationFilename); - } - - /* - * Find out polling time from a parameter. If none is provided, use the - * default (10 seconds). - */ - - String sPollingTime = fc.getInitParameter(POLLING_TIME_PARAM); - - if (sPollingTime != null) { - pollingTime = Long.parseLong(sPollingTime); - } else { - pollingTime = DEFAULT_POLLING_TIME; - } - - /* - * Open up configuration file and populate the AppGuardian configuration - * object. - */ - - FileInputStream inputStream = null; - - try { - String webRootDir = fc.getServletContext().getRealPath("/"); - inputStream = new FileInputStream(configurationFilename); - appGuardConfig = ConfigurationParser.readConfigurationFile(inputStream, webRootDir); - DOMConfigurator.configure(realLogSettingsFilename); - lastConfigReadTime = System.currentTimeMillis(); - } catch (FileNotFoundException e) { - throw new ServletException(e); - } catch (ConfigurationException e) { - throw new ServletException(e); - } finally { - if (inputStream != null) { - try { - inputStream.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - } - - /** - * This is the where the main interception and rule-checking logic of the - * WAF resides. - */ - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) - throws IOException, ServletException { - - /* - * Check to see if polling time has elapsed. If it has, that means we - * should check to see if the config file has been changed. If it has, - * then re-read it. - * - * // TODO: Any reason this logic shouldn't be moved into a polling - * thread class? - */ - - if ((System.currentTimeMillis() - lastConfigReadTime) > pollingTime) { - File f = new File(configurationFilename); - long lastModified = f.lastModified(); - if (lastModified > lastConfigReadTime) { - /* - * The file has been altered since it was read in the last time. - * Must re-read it. - */ - logger.debug(Logger.EVENT_SUCCESS, ">> Re-reading WAF policy"); - init(fc); - } - } - - logger.debug(Logger.EVENT_SUCCESS, ">>In WAF doFilter"); - - HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; - HttpServletResponse httpResponse = (HttpServletResponse) servletResponse; - - InterceptingHTTPServletRequest request = null; - InterceptingHTTPServletResponse response = null; - - /* - * First thing to do is create the InterceptingHTTPServletResponse, - * since we'll need that possibly before the - * InterceptingHTTPServletRequest. - * - * The normal HttpRequest-type objects will suffice us until we get to - * stage 2. - * - * 1st argument = the response to base the instance on 2nd argument = - * should we bother intercepting the egress response? 3rd argument = - * cookie rules because thats where they mostly get acted on - */ - - if (appGuardConfig.getCookieRules().size() + appGuardConfig.getBeforeResponseRules().size() > 0) { - response = new InterceptingHTTPServletResponse(httpResponse, true, appGuardConfig.getCookieRules()); - } - - /* - * Stage 1: Rules that do not need the request body. - */ - logger.debug(Logger.EVENT_SUCCESS, ">> Starting stage 1"); - - List rules = this.appGuardConfig.getBeforeBodyRules(); - - for (int i = 0; i < rules.size(); i++) { - - Rule rule = rules.get(i); - logger.debug(Logger.EVENT_SUCCESS, " Applying BEFORE rule: " + rule.getClass().getName()); - - /* - * The rules execute in check(). The check() method will also log. - * All we have to do is decide what other actions to take. - */ - Action action = rule.check(httpRequest, response, httpResponse); - - if (action.isActionNecessary()) { - - if (action instanceof BlockAction) { - if (response != null) { - response.setStatus(appGuardConfig.getDefaultResponseCode()); - } else { - httpResponse.setStatus(appGuardConfig.getDefaultResponseCode()); - } - return; - - } else if (action instanceof RedirectAction) { - sendRedirect(response, httpResponse, ((RedirectAction) action).getRedirectURL()); - return; - - } else if (action instanceof DefaultAction) { - - switch (AppGuardianConfiguration.DEFAULT_FAIL_ACTION) { - case AppGuardianConfiguration.BLOCK: - if (response != null) { - response.setStatus(appGuardConfig.getDefaultResponseCode()); - } else { - httpResponse.setStatus(appGuardConfig.getDefaultResponseCode()); - } - return; - - case AppGuardianConfiguration.REDIRECT: - sendRedirect(response, httpResponse); - return; - } - } - } - } - - /* - * Create the InterceptingHTTPServletRequest. - */ - - try { - request = new InterceptingHTTPServletRequest((HttpServletRequest) servletRequest); - } catch (FileUploadException fue) { - logger.error(Logger.EVENT_SUCCESS, "Error Wrapping Request", fue); - } - - /* - * Stage 2: After the body has been read, but before the the application - * has gotten it. - */ - logger.debug(Logger.EVENT_SUCCESS, ">> Starting Stage 2"); - - rules = this.appGuardConfig.getAfterBodyRules(); - - for (int i = 0; i < rules.size(); i++) { - - Rule rule = rules.get(i); - logger.debug(Logger.EVENT_SUCCESS, " Applying BEFORE CHAIN rule: " + rule.getClass().getName()); - - /* - * The rules execute in check(). The check() method will take care - * of logging. All we have to do is decide what other actions to - * take. - */ - Action action = rule.check(request, response, httpResponse); - - if (action.isActionNecessary()) { - - if (action instanceof BlockAction) { - if (response != null) { - response.setStatus(appGuardConfig.getDefaultResponseCode()); - } else { - httpResponse.setStatus(appGuardConfig.getDefaultResponseCode()); - } - return; - - } else if (action instanceof RedirectAction) { - sendRedirect(response, httpResponse, ((RedirectAction) action).getRedirectURL()); - return; - - } else if (action instanceof DefaultAction) { - - switch (AppGuardianConfiguration.DEFAULT_FAIL_ACTION) { - case AppGuardianConfiguration.BLOCK: - if (response != null) { - response.setStatus(appGuardConfig.getDefaultResponseCode()); - } else { - httpResponse.setStatus(appGuardConfig.getDefaultResponseCode()); - } - return; - - case AppGuardianConfiguration.REDIRECT: - sendRedirect(response, httpResponse); - return; - } - } - } - } - - /* - * In between stages 2 and 3 is the application's processing of the - * input. - */ - logger.debug(Logger.EVENT_SUCCESS, ">> Calling the FilterChain: " + chain); - chain.doFilter(request, response != null ? response : httpResponse); - - /* - * Stage 3: Before the response has been sent back to the user. - */ - logger.debug(Logger.EVENT_SUCCESS, ">> Starting Stage 3"); - - rules = this.appGuardConfig.getBeforeResponseRules(); - - for (int i = 0; i < rules.size(); i++) { - - Rule rule = rules.get(i); - logger.debug(Logger.EVENT_SUCCESS, " Applying AFTER CHAIN rule: " + rule.getClass().getName()); - - /* - * The rules execute in check(). The check() method will also log. - * All we have to do is decide what other actions to take. - */ - Action action = rule.check(request, response, httpResponse); - - if (action.isActionNecessary()) { - - if (action instanceof BlockAction) { - if (response != null) { - response.setStatus(appGuardConfig.getDefaultResponseCode()); - } else { - httpResponse.setStatus(appGuardConfig.getDefaultResponseCode()); - } - return; - - } else if (action instanceof RedirectAction) { - sendRedirect(response, httpResponse, ((RedirectAction) action).getRedirectURL()); - return; - - } else if (action instanceof DefaultAction) { - - switch (AppGuardianConfiguration.DEFAULT_FAIL_ACTION) { - case AppGuardianConfiguration.BLOCK: - if (response != null) { - response.setStatus(appGuardConfig.getDefaultResponseCode()); - } else { - httpResponse.setStatus(appGuardConfig.getDefaultResponseCode()); - } - return; - - case AppGuardianConfiguration.REDIRECT: - sendRedirect(response, httpResponse); - return; - } - } - } - } - - /* - * Now that we've run our last set of rules we can allow the response to - * go through if we were intercepting. - */ - - if (response != null) { - logger.debug(Logger.EVENT_SUCCESS, ">>> committing reponse"); - response.commit(); - } - } - - /* - * Utility method to send HTTP redirects that automatically determines which - * response class to use. - */ - private void sendRedirect(InterceptingHTTPServletResponse response, HttpServletResponse httpResponse, - String redirectURL) throws IOException { - - if (response != null) { // if we've been buffering everything we clean - // it all out before sending back. - response.reset(); - response.resetBuffer(); - response.sendRedirect(redirectURL); - response.commit(); - } else { - httpResponse.sendRedirect(redirectURL); - } - - } - - public void destroy() { - /* - * Any cleanup necessary? - */ - } - - private void sendRedirect(InterceptingHTTPServletResponse response, HttpServletResponse httpResponse) - throws IOException { - /* - * [chrisisbeef] - commented out as this is not currently used. Minor - * performance tweak. String finalJavaScript = - * AppGuardianConfiguration.JAVASCRIPT_REDIRECT; finalJavaScript = - * finalJavaScript.replaceAll(AppGuardianConfiguration. - * JAVASCRIPT_TARGET_TOKEN, appGuardConfig.getDefaultErrorPage()); - */ - - if (response != null) { - response.reset(); - response.resetBuffer(); - /* - * response.setStatus(appGuardConfig.getDefaultResponseCode()); - * response.getOutputStream().write(finalJavaScript.getBytes()); - */ - response.sendRedirect(appGuardConfig.getDefaultErrorPage()); - - } else { - if (!httpResponse.isCommitted()) { - httpResponse.sendRedirect(appGuardConfig.getDefaultErrorPage()); - } else { - /* - * Can't send redirect because response is already committed. - * I'm not sure how this could happen, but I didn't want to - * cause IOExceptions in case if it ever does. - */ - } - - } - } + private AppGuardianConfiguration appGuardConfig; + + private static final String CONFIGURATION_FILE_PARAM = "configuration"; + private static final String LOGGING_FILE_PARAM = "log_settings"; + private static final String POLLING_TIME_PARAM = "polling_time"; + + private static final int DEFAULT_POLLING_TIME = 30000; + + private String configurationFilename = null; + + private long pollingTime; + + private long lastConfigReadTime; + + // private static final String FAUX_SESSION_COOKIE = "FAUXSC"; + // private static final String SESSION_COOKIE_CANARY = + // "org.owasp.esapi.waf.canary"; + + private FilterConfig fc; + + private final Logger logger = ESAPI.getLogger(ESAPIWebApplicationFirewallFilter.class); + + /** + * This function is used in testing to dynamically alter the configuration. + * + * @param policyFilePath + * The path to the policy file + * @param webRootDir + * The root directory of the web application. + * @throws FileNotFoundException + * if the policy file cannot be located + */ + public void setConfiguration(String policyFilePath, String webRootDir) throws FileNotFoundException { + + FileInputStream inputStream = null; + + try { + inputStream = new FileInputStream(new File(policyFilePath)); + appGuardConfig = ConfigurationParser.readConfigurationFile(inputStream, webRootDir); + lastConfigReadTime = System.currentTimeMillis(); + configurationFilename = policyFilePath; + } catch (ConfigurationException e) { + // TODO: It would be ideal if this method through the + // ConfigurationException rather than catching it and + // writing the error to the console. + e.printStackTrace(); + } finally { + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + public AppGuardianConfiguration getConfiguration() { + return appGuardConfig; + } + + /** + * + * This function is invoked at application startup and when the + * configuration file polling period has elapsed and a change in the + * configuration file has been detected. + * + * It's main purpose is to read the configuration file and establish the + * configuration object model for use at runtime during the + * doFilter() method. + */ + public void init(FilterConfig fc) throws ServletException { + + /* + * This variable is saved so that we can retrieve it later to re-invoke + * this function. + */ + this.fc = fc; + + logger.debug(Logger.EVENT_SUCCESS, ">> Initializing WAF"); + /* + * Pull logging file. + */ + + // Demoted scope to a local since this is the only place it is + // referenced + String logSettingsFilename = fc.getInitParameter(LOGGING_FILE_PARAM); + + String realLogSettingsFilename = fc.getServletContext().getRealPath(logSettingsFilename); + + if (realLogSettingsFilename == null || (!new File(realLogSettingsFilename).exists())) { + throw new ServletException( + "[ESAPI WAF] Could not find log file at resolved path: " + realLogSettingsFilename); + } + + /* + * Pull main configuration file. + */ + + configurationFilename = fc.getInitParameter(CONFIGURATION_FILE_PARAM); + + configurationFilename = fc.getServletContext().getRealPath(configurationFilename); + + if (configurationFilename == null || !new File(configurationFilename).exists()) { + throw new ServletException( + "[ESAPI WAF] Could not find configuration file at resolved path: " + configurationFilename); + } + + /* + * Find out polling time from a parameter. If none is provided, use the + * default (10 seconds). + */ + + String sPollingTime = fc.getInitParameter(POLLING_TIME_PARAM); + + if (sPollingTime != null) { + pollingTime = Long.parseLong(sPollingTime); + } else { + pollingTime = DEFAULT_POLLING_TIME; + } + + /* + * Open up configuration file and populate the AppGuardian configuration + * object. + */ + + FileInputStream inputStream = null; + + try { + String webRootDir = fc.getServletContext().getRealPath("/"); + inputStream = new FileInputStream(configurationFilename); + appGuardConfig = ConfigurationParser.readConfigurationFile(inputStream, webRootDir); + DOMConfigurator.configure(realLogSettingsFilename); + lastConfigReadTime = System.currentTimeMillis(); + } catch (FileNotFoundException e) { + throw new ServletException(e); + } catch (ConfigurationException e) { + throw new ServletException(e); + } finally { + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + /** + * This is the where the main interception and rule-checking logic of the + * WAF resides. + */ + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) + throws IOException, ServletException { + + /* + * Check to see if polling time has elapsed. If it has, that means we + * should check to see if the config file has been changed. If it has, + * then re-read it. + * + * // TODO: Any reason this logic shouldn't be moved into a polling + * thread class? + */ + + if ((System.currentTimeMillis() - lastConfigReadTime) > pollingTime) { + File f = new File(configurationFilename); + long lastModified = f.lastModified(); + if (lastModified > lastConfigReadTime) { + /* + * The file has been altered since it was read in the last time. + * Must re-read it. + */ + logger.debug(Logger.EVENT_SUCCESS, ">> Re-reading WAF policy"); + init(fc); + } + } + + logger.debug(Logger.EVENT_SUCCESS, ">>In WAF doFilter"); + + HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; + HttpServletResponse httpResponse = (HttpServletResponse) servletResponse; + + InterceptingHTTPServletRequest request = null; + InterceptingHTTPServletResponse response = null; + + /* + * First thing to do is create the InterceptingHTTPServletResponse, + * since we'll need that possibly before the + * InterceptingHTTPServletRequest. + * + * The normal HttpRequest-type objects will suffice us until we get to + * stage 2. + * + * 1st argument = the response to base the instance on 2nd argument = + * should we bother intercepting the egress response? 3rd argument = + * cookie rules because thats where they mostly get acted on + */ + + if (appGuardConfig.getCookieRules().size() + appGuardConfig.getBeforeResponseRules().size() > 0) { + response = new InterceptingHTTPServletResponse(httpResponse, true, appGuardConfig.getCookieRules()); + } + + /* + * Stage 1: Rules that do not need the request body. + */ + logger.debug(Logger.EVENT_SUCCESS, ">> Starting stage 1"); + + List rules = this.appGuardConfig.getBeforeBodyRules(); + + for (int i = 0; i < rules.size(); i++) { + + Rule rule = rules.get(i); + logger.debug(Logger.EVENT_SUCCESS, " Applying BEFORE rule: " + rule.getClass().getName()); + + /* + * The rules execute in check(). The check() method will also log. + * All we have to do is decide what other actions to take. + */ + Action action = rule.check(httpRequest, response, httpResponse); + + if (action.isActionNecessary()) { + + if (action instanceof BlockAction) { + if (response != null) { + response.setStatus(appGuardConfig.getDefaultResponseCode()); + } else { + httpResponse.setStatus(appGuardConfig.getDefaultResponseCode()); + } + return; + + } else if (action instanceof RedirectAction) { + sendRedirect(response, httpResponse, ((RedirectAction) action).getRedirectURL()); + return; + + } else if (action instanceof DefaultAction) { + + switch (AppGuardianConfiguration.DEFAULT_FAIL_ACTION) { + case AppGuardianConfiguration.BLOCK: + if (response != null) { + response.setStatus(appGuardConfig.getDefaultResponseCode()); + } else { + httpResponse.setStatus(appGuardConfig.getDefaultResponseCode()); + } + return; + + case AppGuardianConfiguration.REDIRECT: + sendRedirect(response, httpResponse); + return; + } + } + } + } + + /* + * Create the InterceptingHTTPServletRequest. + */ + + try { + request = new InterceptingHTTPServletRequest((HttpServletRequest) servletRequest); + } catch (FileUploadException fue) { + logger.error(Logger.EVENT_SUCCESS, "Error Wrapping Request", fue); + } + + /* + * Stage 2: After the body has been read, but before the the application + * has gotten it. + */ + logger.debug(Logger.EVENT_SUCCESS, ">> Starting Stage 2"); + + rules = this.appGuardConfig.getAfterBodyRules(); + + for (int i = 0; i < rules.size(); i++) { + + Rule rule = rules.get(i); + logger.debug(Logger.EVENT_SUCCESS, " Applying BEFORE CHAIN rule: " + rule.getClass().getName()); + + /* + * The rules execute in check(). The check() method will take care + * of logging. All we have to do is decide what other actions to + * take. + */ + Action action = rule.check(request, response, httpResponse); + + if (action.isActionNecessary()) { + + if (action instanceof BlockAction) { + if (response != null) { + response.setStatus(appGuardConfig.getDefaultResponseCode()); + } else { + httpResponse.setStatus(appGuardConfig.getDefaultResponseCode()); + } + return; + + } else if (action instanceof RedirectAction) { + sendRedirect(response, httpResponse, ((RedirectAction) action).getRedirectURL()); + return; + + } else if (action instanceof DefaultAction) { + + switch (AppGuardianConfiguration.DEFAULT_FAIL_ACTION) { + case AppGuardianConfiguration.BLOCK: + if (response != null) { + response.setStatus(appGuardConfig.getDefaultResponseCode()); + } else { + httpResponse.setStatus(appGuardConfig.getDefaultResponseCode()); + } + return; + + case AppGuardianConfiguration.REDIRECT: + sendRedirect(response, httpResponse); + return; + } + } + } + } + + /* + * In between stages 2 and 3 is the application's processing of the + * input. + */ + logger.debug(Logger.EVENT_SUCCESS, ">> Calling the FilterChain: " + chain); + chain.doFilter(request, response != null ? response : httpResponse); + + /* + * Stage 3: Before the response has been sent back to the user. + */ + logger.debug(Logger.EVENT_SUCCESS, ">> Starting Stage 3"); + + rules = this.appGuardConfig.getBeforeResponseRules(); + + for (int i = 0; i < rules.size(); i++) { + + Rule rule = rules.get(i); + logger.debug(Logger.EVENT_SUCCESS, " Applying AFTER CHAIN rule: " + rule.getClass().getName()); + + /* + * The rules execute in check(). The check() method will also log. + * All we have to do is decide what other actions to take. + */ + Action action = rule.check(request, response, httpResponse); + + if (action.isActionNecessary()) { + + if (action instanceof BlockAction) { + if (response != null) { + response.setStatus(appGuardConfig.getDefaultResponseCode()); + } else { + httpResponse.setStatus(appGuardConfig.getDefaultResponseCode()); + } + return; + + } else if (action instanceof RedirectAction) { + sendRedirect(response, httpResponse, ((RedirectAction) action).getRedirectURL()); + return; + + } else if (action instanceof DefaultAction) { + + switch (AppGuardianConfiguration.DEFAULT_FAIL_ACTION) { + case AppGuardianConfiguration.BLOCK: + if (response != null) { + response.setStatus(appGuardConfig.getDefaultResponseCode()); + } else { + httpResponse.setStatus(appGuardConfig.getDefaultResponseCode()); + } + return; + + case AppGuardianConfiguration.REDIRECT: + sendRedirect(response, httpResponse); + return; + } + } + } + } + + /* + * Now that we've run our last set of rules we can allow the response to + * go through if we were intercepting. + */ + + if (response != null) { + logger.debug(Logger.EVENT_SUCCESS, ">>> committing reponse"); + response.commit(); + } + } + + /* + * Utility method to send HTTP redirects that automatically determines which + * response class to use. + */ + private void sendRedirect(InterceptingHTTPServletResponse response, HttpServletResponse httpResponse, + String redirectURL) throws IOException { + + if (response != null) { // if we've been buffering everything we clean + // it all out before sending back. + response.reset(); + response.resetBuffer(); + response.sendRedirect(redirectURL); + response.commit(); + } else { + httpResponse.sendRedirect(redirectURL); + } + + } + + public void destroy() { + /* + * Any cleanup necessary? + */ + } + + private void sendRedirect(InterceptingHTTPServletResponse response, HttpServletResponse httpResponse) + throws IOException { + /* + * [chrisisbeef] - commented out as this is not currently used. Minor + * performance tweak. String finalJavaScript = + * AppGuardianConfiguration.JAVASCRIPT_REDIRECT; finalJavaScript = + * finalJavaScript.replaceAll(AppGuardianConfiguration. + * JAVASCRIPT_TARGET_TOKEN, appGuardConfig.getDefaultErrorPage()); + */ + + if (response != null) { + response.reset(); + response.resetBuffer(); + /* + * response.setStatus(appGuardConfig.getDefaultResponseCode()); + * response.getOutputStream().write(finalJavaScript.getBytes()); + */ + response.sendRedirect(appGuardConfig.getDefaultErrorPage()); + + } else { + if (!httpResponse.isCommitted()) { + httpResponse.sendRedirect(appGuardConfig.getDefaultErrorPage()); + } else { + /* + * Can't send redirect because response is already committed. + * I'm not sure how this could happen, but I didn't want to + * cause IOExceptions in case if it ever does. + */ + } + + } + } } diff --git a/src/main/java/org/owasp/esapi/waf/actions/Action.java b/src/main/java/org/owasp/esapi/waf/actions/Action.java index b15498ad0..fe8cb3e57 100644 --- a/src/main/java/org/owasp/esapi/waf/actions/Action.java +++ b/src/main/java/org/owasp/esapi/waf/actions/Action.java @@ -23,23 +23,23 @@ */ public abstract class Action { - protected boolean failed = true; - protected boolean actionNecessary = true; + protected boolean failed = true; + protected boolean actionNecessary = true; - public void setFailed(boolean didFail) { - failed = didFail; - } + public void setFailed(boolean didFail) { + failed = didFail; + } - public boolean failedRule() { - return failed; - } + public boolean failedRule() { + return failed; + } - public boolean isActionNecessary() { - return actionNecessary; - } + public boolean isActionNecessary() { + return actionNecessary; + } - public void setActionNecessary(boolean b) { - this.actionNecessary = b; + public void setActionNecessary(boolean b) { + this.actionNecessary = b; - } + } } diff --git a/src/main/java/org/owasp/esapi/waf/actions/BlockAction.java b/src/main/java/org/owasp/esapi/waf/actions/BlockAction.java index 5acfcf157..c216985f2 100644 --- a/src/main/java/org/owasp/esapi/waf/actions/BlockAction.java +++ b/src/main/java/org/owasp/esapi/waf/actions/BlockAction.java @@ -23,13 +23,13 @@ */ public class BlockAction extends Action { - public boolean failedRule() { - return true; - } + public boolean failedRule() { + return true; + } - public boolean isActionNecessary() { - return true; - } + public boolean isActionNecessary() { + return true; + } } diff --git a/src/main/java/org/owasp/esapi/waf/actions/DefaultAction.java b/src/main/java/org/owasp/esapi/waf/actions/DefaultAction.java index dd81431ea..732f3d87e 100644 --- a/src/main/java/org/owasp/esapi/waf/actions/DefaultAction.java +++ b/src/main/java/org/owasp/esapi/waf/actions/DefaultAction.java @@ -23,12 +23,12 @@ */ public class DefaultAction extends Action { - public boolean failedRule() { - return true; - } + public boolean failedRule() { + return true; + } - public boolean isActionNecessary() { - return true; - } + public boolean isActionNecessary() { + return true; + } } diff --git a/src/main/java/org/owasp/esapi/waf/actions/DoNothingAction.java b/src/main/java/org/owasp/esapi/waf/actions/DoNothingAction.java index a75f58888..cd2f58a8a 100644 --- a/src/main/java/org/owasp/esapi/waf/actions/DoNothingAction.java +++ b/src/main/java/org/owasp/esapi/waf/actions/DoNothingAction.java @@ -22,13 +22,13 @@ */ public class DoNothingAction extends Action { - public boolean failedRule() { - return this.failed; - } + public boolean failedRule() { + return this.failed; + } - public boolean isActionNecessary() { - return false; - } + public boolean isActionNecessary() { + return false; + } } diff --git a/src/main/java/org/owasp/esapi/waf/actions/RedirectAction.java b/src/main/java/org/owasp/esapi/waf/actions/RedirectAction.java index 0993b4ad5..f80af4de8 100644 --- a/src/main/java/org/owasp/esapi/waf/actions/RedirectAction.java +++ b/src/main/java/org/owasp/esapi/waf/actions/RedirectAction.java @@ -22,18 +22,18 @@ */ public class RedirectAction extends Action { - private String url = null; + private String url = null; - /* - * Setting this overrides the default value read in the config file. - */ - public void setRedirectURL(String s) { - this.url = s; - } + /* + * Setting this overrides the default value read in the config file. + */ + public void setRedirectURL(String s) { + this.url = s; + } - public String getRedirectURL() { - return this.url; - } + public String getRedirectURL() { + return this.url; + } } diff --git a/src/main/java/org/owasp/esapi/waf/configuration/AppGuardianConfiguration.java b/src/main/java/org/owasp/esapi/waf/configuration/AppGuardianConfiguration.java index 29e398eae..78140cdfc 100644 --- a/src/main/java/org/owasp/esapi/waf/configuration/AppGuardianConfiguration.java +++ b/src/main/java/org/owasp/esapi/waf/configuration/AppGuardianConfiguration.java @@ -31,161 +31,161 @@ */ public class AppGuardianConfiguration { - /* - * Fail modes (BLOCK blocks and logs the request, DONT_BLOCK simply logs) - */ - public static final int LOG = 0; - public static final int REDIRECT = 1; - public static final int BLOCK = 2; - - /* - * The operators. - */ - public static final int OPERATOR_EQ = 0; - public static final int OPERATOR_CONTAINS = 1; - public static final int OPERATOR_IN_LIST = 2; - public static final int OPERATOR_EXISTS = 3; - - /* - * We have static copies of the log settings so that the Rule objects - * can access them, because they don't have access to the instance of - * the configuration object. - */ - public static Level LOG_LEVEL = Level.INFO; - public static String LOG_DIRECTORY = "/WEB-INF/logs"; - - /* - * Logging settings. - */ - private Level logLevel = Level.INFO; - private String logDirectory = "/WEB-INF/logs"; - - /* - * Default settings. - */ - public static int DEFAULT_FAIL_ACTION = LOG; - - // TODO: use UTF-8 - public static String DEFAULT_CHARACTER_ENCODING = "ISO-8859-1"; - public static String DEFAULT_CONTENT_TYPE = "text/html; charset=" + DEFAULT_CHARACTER_ENCODING; - - /* - * The JavaScript to redirect users to the default error page. Have - * to use this because response.sendRedirect() can't have an arbitrary - * response code and that is a requirement. - */ - public static final String JAVASCRIPT_TARGET_TOKEN = "##1##"; - public static final String JAVASCRIPT_REDIRECT = ""; - - /* - * Fail response settings. - */ - private String defaultErrorPage; - private int defaultResponseCode; - - private boolean forceHttpOnlyFlagToSession = false; - private boolean forceSecureFlagToSession = false; - - private String sessionCookieName; - - public String getSessionCookieName() { - return sessionCookieName; - } - - public void setSessionCookieName(String sessionCookieName) { - this.sessionCookieName = sessionCookieName; - } - - /* - * The object-level rules encapsulated by the stage in which they are executed. - */ - private List beforeBodyRules; - private List afterBodyRules; - private List beforeResponseRules; - private List cookieRules; - - public AppGuardianConfiguration() { - beforeBodyRules = new ArrayList(); - afterBodyRules = new ArrayList(); - beforeResponseRules = new ArrayList(); - cookieRules = new ArrayList(); - } - - public String getDefaultErrorPage() { - return defaultErrorPage; - } - - public void setDefaultErrorPage(String defaultErrorPage) { - this.defaultErrorPage = defaultErrorPage; - } - - public int getDefaultResponseCode() { - return defaultResponseCode; - } - - public void setDefaultResponseCode(int defaultResponseCode) { - this.defaultResponseCode = defaultResponseCode; - } - - - public List getBeforeBodyRules() { - return beforeBodyRules; - } - - public List getAfterBodyRules() { - return afterBodyRules; - } - - public List getBeforeResponseRules() { - return beforeResponseRules; - } - - public List getCookieRules() { - return cookieRules; - } - - public void addBeforeBodyRule(Rule r) { - beforeBodyRules.add(r); - } - - public void addAfterBodyRule(Rule r) { - afterBodyRules.add(r); - } - - public void addBeforeResponseRule(Rule r) { - beforeResponseRules.add(r); - } - - public void addCookieRule(Rule r) { - cookieRules.add(r); - } - - public void setApplyHTTPOnlyFlagToSessionCookie(boolean shouldApply) { - forceHttpOnlyFlagToSession = shouldApply; - } - - public void setApplySecureFlagToSessionCookie(boolean shouldApply) { - forceSecureFlagToSession = shouldApply; - } - - public boolean isUsingHttpOnlyFlagOnSessionCookie() { - return forceHttpOnlyFlagToSession; - } - - public boolean isUsingSecureFlagOnSessionCookie() { - return forceSecureFlagToSession; - } - - public String toString() { - StringBuilder sb = new StringBuilder( "WAF Configuration\n" ); - sb.append( "Before body rules:\n" ); - for ( Rule rule : beforeBodyRules ) sb.append( " " + rule.toString() + "\n" ); - sb.append( "After body rules:\n" ); - for ( Rule rule : afterBodyRules ) sb.append( " " + rule.toString() + "\n" ); - sb.append( "Before response rules:\n" ); - for ( Rule rule : beforeResponseRules ) sb.append( " " + rule.toString() + "\n" ); - sb.append( "Cookie rules:\n" ); - for ( Rule rule : cookieRules ) sb.append( " " + rule.toString() + "\n" ); - return sb.toString(); - } + /* + * Fail modes (BLOCK blocks and logs the request, DONT_BLOCK simply logs) + */ + public static final int LOG = 0; + public static final int REDIRECT = 1; + public static final int BLOCK = 2; + + /* + * The operators. + */ + public static final int OPERATOR_EQ = 0; + public static final int OPERATOR_CONTAINS = 1; + public static final int OPERATOR_IN_LIST = 2; + public static final int OPERATOR_EXISTS = 3; + + /* + * We have static copies of the log settings so that the Rule objects + * can access them, because they don't have access to the instance of + * the configuration object. + */ + public static Level LOG_LEVEL = Level.INFO; + public static String LOG_DIRECTORY = "/WEB-INF/logs"; + + /* + * Logging settings. + */ + private Level logLevel = Level.INFO; + private String logDirectory = "/WEB-INF/logs"; + + /* + * Default settings. + */ + public static int DEFAULT_FAIL_ACTION = LOG; + + // TODO: use UTF-8 + public static String DEFAULT_CHARACTER_ENCODING = "ISO-8859-1"; + public static String DEFAULT_CONTENT_TYPE = "text/html; charset=" + DEFAULT_CHARACTER_ENCODING; + + /* + * The JavaScript to redirect users to the default error page. Have + * to use this because response.sendRedirect() can't have an arbitrary + * response code and that is a requirement. + */ + public static final String JAVASCRIPT_TARGET_TOKEN = "##1##"; + public static final String JAVASCRIPT_REDIRECT = ""; + + /* + * Fail response settings. + */ + private String defaultErrorPage; + private int defaultResponseCode; + + private boolean forceHttpOnlyFlagToSession = false; + private boolean forceSecureFlagToSession = false; + + private String sessionCookieName; + + public String getSessionCookieName() { + return sessionCookieName; + } + + public void setSessionCookieName(String sessionCookieName) { + this.sessionCookieName = sessionCookieName; + } + + /* + * The object-level rules encapsulated by the stage in which they are executed. + */ + private List beforeBodyRules; + private List afterBodyRules; + private List beforeResponseRules; + private List cookieRules; + + public AppGuardianConfiguration() { + beforeBodyRules = new ArrayList(); + afterBodyRules = new ArrayList(); + beforeResponseRules = new ArrayList(); + cookieRules = new ArrayList(); + } + + public String getDefaultErrorPage() { + return defaultErrorPage; + } + + public void setDefaultErrorPage(String defaultErrorPage) { + this.defaultErrorPage = defaultErrorPage; + } + + public int getDefaultResponseCode() { + return defaultResponseCode; + } + + public void setDefaultResponseCode(int defaultResponseCode) { + this.defaultResponseCode = defaultResponseCode; + } + + + public List getBeforeBodyRules() { + return beforeBodyRules; + } + + public List getAfterBodyRules() { + return afterBodyRules; + } + + public List getBeforeResponseRules() { + return beforeResponseRules; + } + + public List getCookieRules() { + return cookieRules; + } + + public void addBeforeBodyRule(Rule r) { + beforeBodyRules.add(r); + } + + public void addAfterBodyRule(Rule r) { + afterBodyRules.add(r); + } + + public void addBeforeResponseRule(Rule r) { + beforeResponseRules.add(r); + } + + public void addCookieRule(Rule r) { + cookieRules.add(r); + } + + public void setApplyHTTPOnlyFlagToSessionCookie(boolean shouldApply) { + forceHttpOnlyFlagToSession = shouldApply; + } + + public void setApplySecureFlagToSessionCookie(boolean shouldApply) { + forceSecureFlagToSession = shouldApply; + } + + public boolean isUsingHttpOnlyFlagOnSessionCookie() { + return forceHttpOnlyFlagToSession; + } + + public boolean isUsingSecureFlagOnSessionCookie() { + return forceSecureFlagToSession; + } + + public String toString() { + StringBuilder sb = new StringBuilder( "WAF Configuration\n" ); + sb.append( "Before body rules:\n" ); + for ( Rule rule : beforeBodyRules ) sb.append( " " + rule.toString() + "\n" ); + sb.append( "After body rules:\n" ); + for ( Rule rule : afterBodyRules ) sb.append( " " + rule.toString() + "\n" ); + sb.append( "Before response rules:\n" ); + for ( Rule rule : beforeResponseRules ) sb.append( " " + rule.toString() + "\n" ); + sb.append( "Cookie rules:\n" ); + for ( Rule rule : cookieRules ) sb.append( " " + rule.toString() + "\n" ); + return sb.toString(); + } } diff --git a/src/main/java/org/owasp/esapi/waf/configuration/ConfigurationParser.java b/src/main/java/org/owasp/esapi/waf/configuration/ConfigurationParser.java index fefcff8d5..0370d2ec2 100644 --- a/src/main/java/org/owasp/esapi/waf/configuration/ConfigurationParser.java +++ b/src/main/java/org/owasp/esapi/waf/configuration/ConfigurationParser.java @@ -59,538 +59,538 @@ */ public class ConfigurationParser { - private static final String REGEX = "regex"; - private static final String DEFAULT_PATH_APPLY_ALL = ".*"; - private static final int DEFAULT_RESPONSE_CODE = 403; - private static final String DEFAULT_SESSION_COOKIE; - - static { - String sessionIdName = null; - try { - sessionIdName = ESAPI.securityConfiguration().getHttpSessionIdName(); - } catch (Throwable t) { - sessionIdName = "JSESSIONID"; // If all else fails... - } - DEFAULT_SESSION_COOKIE = sessionIdName; - } - - private static final String[] STAGES = { - "before-request-body", - "after-request-body", - "before-response" - }; - - public static AppGuardianConfiguration readConfigurationFile(InputStream stream, String webRootDir) throws ConfigurationException { - - AppGuardianConfiguration config = new AppGuardianConfiguration(); - - Builder parser = new Builder(); - Document doc; - Element root; - - try { - - doc = parser.build(stream); - root = doc.getRootElement(); - - Element settingsRoot = root.getFirstChildElement("settings"); - Element authNRoot = root.getFirstChildElement("authentication-rules"); - Element authZRoot = root.getFirstChildElement("authorization-rules"); - Element urlRoot = root.getFirstChildElement("url-rules"); - Element headerRoot = root.getFirstChildElement("header-rules"); - Element customRulesRoot = root.getFirstChildElement("custom-rules");; - Element virtualPatchesRoot = root.getFirstChildElement("virtual-patches"); - Element outboundRoot = root.getFirstChildElement("outbound-rules"); - Element beanShellRoot = root.getFirstChildElement("bean-shell-rules"); - - - /** - * Parse the 'settings' section. - */ - if ( settingsRoot == null ) { + private static final String REGEX = "regex"; + private static final String DEFAULT_PATH_APPLY_ALL = ".*"; + private static final int DEFAULT_RESPONSE_CODE = 403; + private static final String DEFAULT_SESSION_COOKIE; + + static { + String sessionIdName = null; + try { + sessionIdName = ESAPI.securityConfiguration().getHttpSessionIdName(); + } catch (Throwable t) { + sessionIdName = "JSESSIONID"; // If all else fails... + } + DEFAULT_SESSION_COOKIE = sessionIdName; + } + + private static final String[] STAGES = { + "before-request-body", + "after-request-body", + "before-response" + }; + + public static AppGuardianConfiguration readConfigurationFile(InputStream stream, String webRootDir) throws ConfigurationException { + + AppGuardianConfiguration config = new AppGuardianConfiguration(); + + Builder parser = new Builder(); + Document doc; + Element root; + + try { + + doc = parser.build(stream); + root = doc.getRootElement(); + + Element settingsRoot = root.getFirstChildElement("settings"); + Element authNRoot = root.getFirstChildElement("authentication-rules"); + Element authZRoot = root.getFirstChildElement("authorization-rules"); + Element urlRoot = root.getFirstChildElement("url-rules"); + Element headerRoot = root.getFirstChildElement("header-rules"); + Element customRulesRoot = root.getFirstChildElement("custom-rules");; + Element virtualPatchesRoot = root.getFirstChildElement("virtual-patches"); + Element outboundRoot = root.getFirstChildElement("outbound-rules"); + Element beanShellRoot = root.getFirstChildElement("bean-shell-rules"); + + + /** + * Parse the 'settings' section. + */ + if ( settingsRoot == null ) { throw new ConfigurationException("", "The section is required"); - } else if ( settingsRoot != null ) { - - - try { - String sessionCookieName = settingsRoot.getFirstChildElement("session-cookie-name").getValue(); - if ( ! "".equals(sessionCookieName) ) { - config.setSessionCookieName(sessionCookieName); - } - } catch (NullPointerException npe) { - config.setSessionCookieName(DEFAULT_SESSION_COOKIE); - } - - String mode = settingsRoot.getFirstChildElement("mode").getValue(); - - if ( "block".equals(mode.toLowerCase() ) ) { - AppGuardianConfiguration.DEFAULT_FAIL_ACTION = AppGuardianConfiguration.BLOCK; - } else if ( "redirect".equals(mode.toLowerCase() ) ){ - AppGuardianConfiguration.DEFAULT_FAIL_ACTION = AppGuardianConfiguration.REDIRECT; - } else { - AppGuardianConfiguration.DEFAULT_FAIL_ACTION = AppGuardianConfiguration.LOG; - } - - Element errorHandlingRoot = settingsRoot.getFirstChildElement("error-handling"); - - config.setDefaultErrorPage( errorHandlingRoot.getFirstChildElement("default-redirect-page").getValue() ); - - try { - config.setDefaultResponseCode( Integer.parseInt(errorHandlingRoot.getFirstChildElement("block-status").getValue()) ); - } catch (Exception e) { - config.setDefaultResponseCode( DEFAULT_RESPONSE_CODE ); - } - } - - /** - * Parse the 'authentication-rules' section if they have one. - */ - if ( authNRoot != null ) { - String key = authNRoot.getAttributeValue("key"); - String path = authNRoot.getAttributeValue("path"); - String id = authNRoot.getAttributeValue("id"); - - if ( path != null && key != null ) { - config.addBeforeBodyRule(new AuthenticatedRule(id,key,Pattern.compile(path),getExceptionsFromElement(authNRoot))); - } else if ( key != null ) { - config.addBeforeBodyRule(new AuthenticatedRule(id,key,null,getExceptionsFromElement(authNRoot))); - } else { - throw new ConfigurationException("","The rule requires a 'key' attribute"); - } - } - - /** - * Parse 'authorization-rules' section if they have one. - */ - - if ( authZRoot != null ) { - - Elements restrictNodes = authZRoot.getChildElements("restrict-source-ip"); - - for(int i=0;i rule requires a 'key' attribute"); + } + } + + /** + * Parse 'authorization-rules' section if they have one. + */ + + if ( authZRoot != null ) { + + Elements restrictNodes = authZRoot.getChildElements("restrict-source-ip"); + + for(int i=0;i exceptions = getExceptionsFromElement(e); + Element e = enforceHttpsNodes.get(i); + String path = e.getAttributeValue("path"); + String action = e.getAttributeValue("action"); + String id = e.getAttributeValue("id"); + List exceptions = getExceptionsFromElement(e); - config.addBeforeBodyRule( new EnforceHTTPSRule(id, Pattern.compile(path), exceptions, action) ); - } + config.addBeforeBodyRule( new EnforceHTTPSRule(id, Pattern.compile(path), exceptions, action) ); + } - } + } - if ( headerRoot != null ) { + if ( headerRoot != null ) { - Elements restrictContentTypes = headerRoot.getChildElements("restrict-content-type"); - Elements restrictUserAgents = headerRoot.getChildElements("restrict-user-agent"); + Elements restrictContentTypes = headerRoot.getChildElements("restrict-content-type"); + Elements restrictUserAgents = headerRoot.getChildElements("restrict-user-agent"); - for(int i=0;i rules. This could be used to add: - * - X-I-DONT-WANT-TO-BE-FRAMED - * - Caching prevention headers - * - Custom application headers - */ - - Elements addHeaderNodes = outboundRoot.getChildElements("add-header"); - - for(int i=0;i rules that allow - * us to add the HTTPOnly flag to cookies, both - * custom and app server. - */ - Elements addHTTPOnlyFlagNodes = outboundRoot.getChildElements("add-http-only-flag"); - - for(int i=0;i patterns = new ArrayList(); - - for(int j=0;j rules that allow - * us to add the secure flag to cookies, both - * custom and app server. - */ - Elements addSecureFlagNodes = outboundRoot.getChildElements("add-secure-flag"); - - for(int i=0;i patterns = new ArrayList(); - - for(int j=0;j rules must contain a 'pattern' attribute"); - } else if ( contentType == null ) { - throw new ConfigurationException("", " rules must contain a 'content-type' attribute"); - } - - DetectOutboundContentRule docr = new DetectOutboundContentRule( - id, - Pattern.compile(contentType), - Pattern.compile(token,Pattern.DOTALL), - path != null ? Pattern.compile(path) : null); - - config.addBeforeResponseRule(docr); - - } - - } - - /** - * Parse the 'bean-shell-rules' section. - */ - - if ( beanShellRoot != null ) { - - Elements beanShellRules = beanShellRoot.getChildElements("bean-shell-script"); - - for (int i=0;i getExceptionsFromElement(Element root) { - Elements exceptions = root.getChildElements("path-exception"); - ArrayList exceptionList = new ArrayList(); - - for(int i=0;i rules. This could be used to add: + * - X-I-DONT-WANT-TO-BE-FRAMED + * - Caching prevention headers + * - Custom application headers + */ + + Elements addHeaderNodes = outboundRoot.getChildElements("add-header"); + + for(int i=0;i rules that allow + * us to add the HTTPOnly flag to cookies, both + * custom and app server. + */ + Elements addHTTPOnlyFlagNodes = outboundRoot.getChildElements("add-http-only-flag"); + + for(int i=0;i patterns = new ArrayList(); + + for(int j=0;j rules that allow + * us to add the secure flag to cookies, both + * custom and app server. + */ + Elements addSecureFlagNodes = outboundRoot.getChildElements("add-secure-flag"); + + for(int i=0;i patterns = new ArrayList(); + + for(int j=0;j rules must contain a 'pattern' attribute"); + } else if ( contentType == null ) { + throw new ConfigurationException("", " rules must contain a 'content-type' attribute"); + } + + DetectOutboundContentRule docr = new DetectOutboundContentRule( + id, + Pattern.compile(contentType), + Pattern.compile(token,Pattern.DOTALL), + path != null ? Pattern.compile(path) : null); + + config.addBeforeResponseRule(docr); + + } + + } + + /** + * Parse the 'bean-shell-rules' section. + */ + + if ( beanShellRoot != null ) { + + Elements beanShellRules = beanShellRoot.getChildElements("bean-shell-script"); + + for (int i=0;i getExceptionsFromElement(Element root) { + Elements exceptions = root.getChildElements("path-exception"); + ArrayList exceptionList = new ArrayList(); + + for(int i=0;i allParameters; - private Vector allParameterNames; - private static int CHUNKED_BUFFER_SIZE = 1024; - - private boolean isMultipart = false; - private RandomAccessFile requestBody; - private RAFInputStream is; - - public ServletInputStream getInputStream() throws IOException { - - if ( isMultipart ) { - return is; - } else { - return super.getInputStream(); - } + private Vector allParameters; + private Vector allParameterNames; + private static int CHUNKED_BUFFER_SIZE = 1024; + + private boolean isMultipart = false; + private RandomAccessFile requestBody; + private RAFInputStream is; + + public ServletInputStream getInputStream() throws IOException { + + if ( isMultipart ) { + return is; + } else { + return super.getInputStream(); + } } - - public BufferedReader getReader() throws IOException { + + public BufferedReader getReader() throws IOException { String enc = getCharacterEncoding(); if(enc == null) enc = "UTF-8"; return new BufferedReader(new InputStreamReader(getInputStream(), enc)); } - - public InterceptingHTTPServletRequest(HttpServletRequest request) throws FileUploadException, IOException { - - super(request); - - allParameters = new Vector(); - allParameterNames = new Vector(); - - - /* - * Get all the regular parameters. - */ - - Enumeration e = request.getParameterNames(); - - while(e.hasMoreElements()) { - String param = (String)e.nextElement(); - allParameters.add(new Parameter(param,request.getParameter(param),false)); - allParameterNames.add(param); - } - - - /* - * Get all the multipart fields. - */ - - isMultipart = ServletFileUpload.isMultipartContent(request); - - if ( isMultipart ) { - - requestBody = new RandomAccessFile( File.createTempFile("oew","mpc"), "rw"); - - byte buffer[] = new byte[CHUNKED_BUFFER_SIZE]; - - long size = 0; - int len = 0; - - while ( len != -1 && size <= Integer.MAX_VALUE) { - len = request.getInputStream().read(buffer, 0, CHUNKED_BUFFER_SIZE); - if ( len != -1 ) { - size += len; - requestBody.write(buffer,0,len); - } - } - - is = new RAFInputStream(requestBody); - - ServletFileUpload sfu = new ServletFileUpload(); - FileItemIterator iter = sfu.getItemIterator(this); - - while(iter.hasNext()) { - FileItemStream item = iter.next(); - String name = item.getFieldName(); - InputStream stream = item.openStream(); - - /* - * If this is a regular form field, add it to our - * parameter collection. - */ - - if (item.isFormField()) { - - String value = Streams.asString(stream); - - allParameters.add(new Parameter(name,value,true)); - allParameterNames.add(name); - - } else { - /* - * This is a multipart content that is not a - * regular form field. Nothing to do here. - */ - - } - - } - - requestBody.seek(0); - - } - - } - - public String getDictionaryParameter(String s) { - - for(int i=0;i(); + allParameterNames = new Vector(); + + + /* + * Get all the regular parameters. + */ + + Enumeration e = request.getParameterNames(); + + while(e.hasMoreElements()) { + String param = (String)e.nextElement(); + allParameters.add(new Parameter(param,request.getParameter(param),false)); + allParameterNames.add(param); + } + + + /* + * Get all the multipart fields. + */ + + isMultipart = ServletFileUpload.isMultipartContent(request); + + if ( isMultipart ) { + + requestBody = new RandomAccessFile( File.createTempFile("oew","mpc"), "rw"); + + byte buffer[] = new byte[CHUNKED_BUFFER_SIZE]; + + long size = 0; + int len = 0; + + while ( len != -1 && size <= Integer.MAX_VALUE) { + len = request.getInputStream().read(buffer, 0, CHUNKED_BUFFER_SIZE); + if ( len != -1 ) { + size += len; + requestBody.write(buffer,0,len); + } + } + + is = new RAFInputStream(requestBody); + + ServletFileUpload sfu = new ServletFileUpload(); + FileItemIterator iter = sfu.getItemIterator(this); + + while(iter.hasNext()) { + FileItemStream item = iter.next(); + String name = item.getFieldName(); + InputStream stream = item.openStream(); + + /* + * If this is a regular form field, add it to our + * parameter collection. + */ + + if (item.isFormField()) { + + String value = Streams.asString(stream); + + allParameters.add(new Parameter(name,value,true)); + allParameterNames.add(name); + + } else { + /* + * This is a multipart content that is not a + * regular form field. Nothing to do here. + */ + + } + + } + + requestBody.seek(0); + + } + + } + + public String getDictionaryParameter(String s) { + + for(int i=0;i addSecureFlagRules = null; - private List addHTTPOnlyFlagRules = null; - private boolean alreadyCalledWriter = false; - private boolean alreadyCalledOutputStream = false; - - public InterceptingHTTPServletResponse(HttpServletResponse response, boolean buffering, List cookieRules) throws IOException { - - super(response); - - this.contentType = response.getContentType(); - - this.isos = new InterceptingServletOutputStream(response.getOutputStream(), buffering); - this.ipw = new InterceptingPrintWriter(new PrintWriter(isos)); - - addSecureFlagRules = new ArrayList(); - addHTTPOnlyFlagRules = new ArrayList(); - - for(int i=0;i addSecureFlagRules = null; + private List addHTTPOnlyFlagRules = null; + private boolean alreadyCalledWriter = false; + private boolean alreadyCalledOutputStream = false; + + public InterceptingHTTPServletResponse(HttpServletResponse response, boolean buffering, List cookieRules) throws IOException { + + super(response); + + this.contentType = response.getContentType(); + + this.isos = new InterceptingServletOutputStream(response.getOutputStream(), buffering); + this.ipw = new InterceptingPrintWriter(new PrintWriter(isos)); + + addSecureFlagRules = new ArrayList(); + addHTTPOnlyFlagRules = new ArrayList(); + + for(int i=0;i=[; =][; expires=][; // domain=][; path=][; secure][;HttpOnly String header = name + "=" + value; if ( ! isTemporary ) { - header += "; Max-Age=" + maxAge; + header += "; Max-Age=" + maxAge; } if (domain != null) { @@ -173,11 +173,11 @@ private String createCookieHeader(String name, String value, int maxAge, String } if ( secure ) { - header += "; Secure"; + header += "; Secure"; } if (httpOnly) { - header += "; HttpOnly"; + header += "; HttpOnly"; } return header; diff --git a/src/main/java/org/owasp/esapi/waf/internal/InterceptingPrintWriter.java b/src/main/java/org/owasp/esapi/waf/internal/InterceptingPrintWriter.java index a1564509c..4a7962669 100644 --- a/src/main/java/org/owasp/esapi/waf/internal/InterceptingPrintWriter.java +++ b/src/main/java/org/owasp/esapi/waf/internal/InterceptingPrintWriter.java @@ -30,153 +30,153 @@ */ public class InterceptingPrintWriter extends PrintWriter { - public InterceptingPrintWriter(Writer out) { - super(out); - } + public InterceptingPrintWriter(Writer out) { + super(out); + } - public PrintWriter append(char c) { - return super.append(c); - } + public PrintWriter append(char c) { + return super.append(c); + } - public PrintWriter append(CharSequence csq, int start, int end) { - return super.append(csq, start, end); - } + public PrintWriter append(CharSequence csq, int start, int end) { + return super.append(csq, start, end); + } - public PrintWriter append(CharSequence csq) { - return super.append(csq); - } + public PrintWriter append(CharSequence csq) { + return super.append(csq); + } - public boolean checkError() { - return super.checkError(); - } + public boolean checkError() { + return super.checkError(); + } // Java 1.6 only -// protected void clearError() { -// super.clearError(); -// } +// protected void clearError() { +// super.clearError(); +// } - public void close() { - super.close(); - } + public void close() { + super.close(); + } - public void flush() { - super.flush(); - } + public void flush() { + super.flush(); + } - public PrintWriter format(Locale l, String format, Object... args) { - return super.format(l, format, args); - } + public PrintWriter format(Locale l, String format, Object... args) { + return super.format(l, format, args); + } - public PrintWriter format(String format, Object... args) { - return super.format(format, args); - } + public PrintWriter format(String format, Object... args) { + return super.format(format, args); + } - public void print(boolean b) { - super.print(b); - } + public void print(boolean b) { + super.print(b); + } - public void print(char c) { - super.print(c); - } + public void print(char c) { + super.print(c); + } - public void print(char[] s) { - super.print(s); - } + public void print(char[] s) { + super.print(s); + } - public void print(double d) { - super.print(d); - } + public void print(double d) { + super.print(d); + } - public void print(float f) { - super.print(f); - } + public void print(float f) { + super.print(f); + } - public void print(int i) { - super.print(i); - } + public void print(int i) { + super.print(i); + } - public void print(long l) { - super.print(l); - } + public void print(long l) { + super.print(l); + } - public void print(Object obj) { - super.print(obj); - } + public void print(Object obj) { + super.print(obj); + } - public void print(String s) { - super.print(s); - } + public void print(String s) { + super.print(s); + } - public PrintWriter printf(Locale l, String format, Object... args) { - return super.printf(l, format, args); - } + public PrintWriter printf(Locale l, String format, Object... args) { + return super.printf(l, format, args); + } - public PrintWriter printf(String format, Object... args) { - return super.printf(format, args); - } + public PrintWriter printf(String format, Object... args) { + return super.printf(format, args); + } - public void println() { - super.println(); - } + public void println() { + super.println(); + } - public void println(boolean x) { - super.println(x); - } + public void println(boolean x) { + super.println(x); + } - public void println(char x) { - super.println(x); - } + public void println(char x) { + super.println(x); + } - public void println(char[] x) { - super.println(x); - } + public void println(char[] x) { + super.println(x); + } - public void println(double x) { - super.println(x); - } + public void println(double x) { + super.println(x); + } - public void println(float x) { - super.println(x); - } + public void println(float x) { + super.println(x); + } - public void println(int x) { - super.println(x); - } + public void println(int x) { + super.println(x); + } - public void println(long x) { - super.println(x); - } + public void println(long x) { + super.println(x); + } - public void println(Object x) { - super.println(x); - } + public void println(Object x) { + super.println(x); + } - public void println(String x) { - super.println(x); - } + public void println(String x) { + super.println(x); + } - protected void setError() { - super.setError(); - } + protected void setError() { + super.setError(); + } - public void write(char[] buf, int off, int len) { - super.write(buf, off, len); - } + public void write(char[] buf, int off, int len) { + super.write(buf, off, len); + } - public void write(char[] buf) { - super.write(buf); - } + public void write(char[] buf) { + super.write(buf); + } - public void write(int c) { - super.write(c); - } + public void write(int c) { + super.write(c); + } - public void write(String s, int off, int len) { - super.write(s, off, len); - } + public void write(String s, int off, int len) { + super.write(s, off, len); + } - public void write(String s) { - super.write(s); - } + public void write(String s) { + super.write(s); + } } diff --git a/src/main/java/org/owasp/esapi/waf/internal/InterceptingServletOutputStream.java b/src/main/java/org/owasp/esapi/waf/internal/InterceptingServletOutputStream.java index 8dcac0048..1f2ced68e 100644 --- a/src/main/java/org/owasp/esapi/waf/internal/InterceptingServletOutputStream.java +++ b/src/main/java/org/owasp/esapi/waf/internal/InterceptingServletOutputStream.java @@ -37,139 +37,139 @@ public class InterceptingServletOutputStream extends ServletOutputStream { - private static final int FLUSH_BLOCK_SIZE = 1024; - private ServletOutputStream os; - private boolean buffering; - private boolean committed; - private boolean closed; - - private RandomAccessFile out; - - public InterceptingServletOutputStream(ServletOutputStream os, boolean buffered) throws FileNotFoundException, IOException { - super(); - this.os = os; - this.buffering = buffered; - this.committed = false; - this.closed = false; - - /* - * Creating a RandomAccessFile to keep track of output generated. I made - * the prefix and suffix small for less processing. The "oew" is intended - * to stand for "OWASP ESAPI WAF" and the "hop" for HTTP output. - */ - File tempFile= File.createTempFile("oew", ".hop"); - this.out = new RandomAccessFile (tempFile, "rw" ); - tempFile.deleteOnExit(); - - } - - public void reset() throws IOException { - out.setLength(0L); - } - - public byte[] getResponseBytes() throws IOException { - - byte[] buffer = new byte[(int) out.length()]; - out.seek(0); - out.read(buffer, 0, (int)out.length()); - out.seek(out.length()); - return buffer; - - } - - public void setResponseBytes(byte[] responseBytes) throws IOException { - - if ( ! buffering && out.length() > 0 ) { - throw new IOException("Already committed response because not currently buffering"); - } - - out.setLength(0L); - out.write(responseBytes); - } - - public void write(int i) throws IOException { - if (!buffering) { - os.write(i); - } - out.write(i); - } - - public void write(byte[] b) throws IOException { + private static final int FLUSH_BLOCK_SIZE = 1024; + private ServletOutputStream os; + private boolean buffering; + private boolean committed; + private boolean closed; + + private RandomAccessFile out; + + public InterceptingServletOutputStream(ServletOutputStream os, boolean buffered) throws FileNotFoundException, IOException { + super(); + this.os = os; + this.buffering = buffered; + this.committed = false; + this.closed = false; + + /* + * Creating a RandomAccessFile to keep track of output generated. I made + * the prefix and suffix small for less processing. The "oew" is intended + * to stand for "OWASP ESAPI WAF" and the "hop" for HTTP output. + */ + File tempFile= File.createTempFile("oew", ".hop"); + this.out = new RandomAccessFile (tempFile, "rw" ); + tempFile.deleteOnExit(); + + } + + public void reset() throws IOException { + out.setLength(0L); + } + + public byte[] getResponseBytes() throws IOException { + + byte[] buffer = new byte[(int) out.length()]; + out.seek(0); + out.read(buffer, 0, (int)out.length()); + out.seek(out.length()); + return buffer; + + } + + public void setResponseBytes(byte[] responseBytes) throws IOException { + + if ( ! buffering && out.length() > 0 ) { + throw new IOException("Already committed response because not currently buffering"); + } + + out.setLength(0L); + out.write(responseBytes); + } + + public void write(int i) throws IOException { if (!buffering) { - os.write(b, 0, b.length); + os.write(i); + } + out.write(i); + } + + public void write(byte[] b) throws IOException { + if (!buffering) { + os.write(b, 0, b.length); } out.write(b, 0, b.length); } - public void write(byte[] b, int off, int len) throws IOException { + public void write(byte[] b, int off, int len) throws IOException { if (!buffering) { - os.write(b, off, len); + os.write(b, off, len); } out.write(b, off, len); } - public void flush() throws IOException { - - if (buffering) { - - synchronized(out) { - - out.seek(0); - - byte[] buff = new byte[FLUSH_BLOCK_SIZE]; - - for(int i=0;i name; + private List name; - public AddHTTPOnlyFlagRule(String id, List name) { - setId(id); - this.name = name; - } + public AddHTTPOnlyFlagRule(String id, List name) { + setId(id); + this.name = name; + } - public Action check(HttpServletRequest request, - InterceptingHTTPServletResponse response, - HttpServletResponse httpResponse) { + public Action check(HttpServletRequest request, + InterceptingHTTPServletResponse response, + HttpServletResponse httpResponse) { - DoNothingAction action = new DoNothingAction(); + DoNothingAction action = new DoNothingAction(); - return action; - } + return action; + } - public boolean doesCookieMatch(String cookieName) { + public boolean doesCookieMatch(String cookieName) { - for(int i=0;i exceptions; - - public AddHeaderRule(String id, String header, String value, Pattern path, List exceptions) { - setId(id); - this.header = header; - this.value = value; - this.path = path; - this.exceptions = exceptions; - } - - public Action check( - HttpServletRequest request, - InterceptingHTTPServletResponse response, - HttpServletResponse httpResponse) { - - DoNothingAction action = new DoNothingAction(); - - if ( path.matcher(request.getRequestURI()).matches() ) { - - for(int i=0;i exceptions; + + public AddHeaderRule(String id, String header, String value, Pattern path, List exceptions) { + setId(id); + this.header = header; + this.value = value; + this.path = path; + this.exceptions = exceptions; + } + + public Action check( + HttpServletRequest request, + InterceptingHTTPServletResponse response, + HttpServletResponse httpResponse) { + + DoNothingAction action = new DoNothingAction(); + + if ( path.matcher(request.getRequestURI()).matches() ) { + + for(int i=0;i name; + private List name; - public AddSecureFlagRule(String id, List name) { - this.name = name; - setId(id); - } + public AddSecureFlagRule(String id, List name) { + this.name = name; + setId(id); + } - public Action check(HttpServletRequest request, - InterceptingHTTPServletResponse response, - HttpServletResponse httpResponse) { - - DoNothingAction action = new DoNothingAction(); + public Action check(HttpServletRequest request, + InterceptingHTTPServletResponse response, + HttpServletResponse httpResponse) { + + DoNothingAction action = new DoNothingAction(); - return action; - } + return action; + } - public boolean doesCookieMatch(String cookieName) { + public boolean doesCookieMatch(String cookieName) { - for(int i=0;i exceptions; + private String sessionAttribute; + private Pattern path; + private List exceptions; - public AuthenticatedRule(String id, String sessionAttribute, Pattern path, List exceptions) { - this.sessionAttribute = sessionAttribute; - this.path = path; - this.exceptions = exceptions; - setId(id); - } + public AuthenticatedRule(String id, String sessionAttribute, Pattern path, List exceptions) { + this.sessionAttribute = sessionAttribute; + this.path = path; + this.exceptions = exceptions; + setId(id); + } - public Action check(HttpServletRequest request, - InterceptingHTTPServletResponse response, - HttpServletResponse httpResponse) { + public Action check(HttpServletRequest request, + InterceptingHTTPServletResponse response, + HttpServletResponse httpResponse) { - HttpSession session = request.getSession(); - String uri = request.getRequestURI(); + HttpSession session = request.getSession(); + String uri = request.getRequestURI(); - if ( path != null && ! path.matcher(uri).matches() ) { - return new DoNothingAction(); - } + if ( path != null && ! path.matcher(uri).matches() ) { + return new DoNothingAction(); + } - if ( session != null && session.getAttribute(sessionAttribute) != null ) { + if ( session != null && session.getAttribute(sessionAttribute) != null ) { - return new DoNothingAction(); + return new DoNothingAction(); - } else { /* check if it's one of the exceptions */ + } else { /* check if it's one of the exceptions */ - Iterator it = exceptions.iterator(); + Iterator it = exceptions.iterator(); - while(it.hasNext()) { - Object o = it.next(); - if ( o instanceof Pattern ) { + while(it.hasNext()) { + Object o = it.next(); + if ( o instanceof Pattern ) { - Pattern p = (Pattern)o; - if ( p.matcher(uri).matches() ) { - return new DoNothingAction(); - } + Pattern p = (Pattern)o; + if ( p.matcher(uri).matches() ) { + return new DoNothingAction(); + } - } else if ( o instanceof String ) { + } else if ( o instanceof String ) { - if ( uri.equals((String)o)) { - return new DoNothingAction(); - } + if ( uri.equals((String)o)) { + return new DoNothingAction(); + } - } - } - } + } + } + } - log(request, "User requested unauthenticated access to URI '" + request.getRequestURI() + "' [querystring="+request.getQueryString()+"]"); + log(request, "User requested unauthenticated access to URI '" + request.getRequestURI() + "' [querystring="+request.getQueryString()+"]"); - return new DefaultAction(); - } + return new DefaultAction(); + } } diff --git a/src/main/java/org/owasp/esapi/waf/rules/BeanShellRule.java b/src/main/java/org/owasp/esapi/waf/rules/BeanShellRule.java index f90da574e..254c6a70e 100644 --- a/src/main/java/org/owasp/esapi/waf/rules/BeanShellRule.java +++ b/src/main/java/org/owasp/esapi/waf/rules/BeanShellRule.java @@ -40,80 +40,80 @@ */ public class BeanShellRule extends Rule { - private Interpreter i; - private String script; - private Pattern path; - - public BeanShellRule(String fileLocation, String id, Pattern path) throws IOException, EvalError { - i = new Interpreter(); - i.set("logger", logger); - this.script = getFileContents(ESAPI.securityConfiguration().getResourceFile(fileLocation)); - this.id = id; - this.path = path; - } - - public Action check(HttpServletRequest request, InterceptingHTTPServletResponse response, - HttpServletResponse httpResponse) { - - /* - * Early fail: if the URL doesn't match one we're interested in. - */ - - if (path != null && !path.matcher(request.getRequestURI()).matches()) { - return new DoNothingAction(); - } - - /* - * Run the beanshell that we've already parsed and pre-compiled. - * Populate the "request" and "response" objects so the script has - * access to the same variables we do here. - */ - - try { - - Action a = null; - - i.set("action", a); - i.set("request", request); - - if (response != null) { - i.set("response", response); - } else { - i.set("response", httpResponse); - } - - i.set("session", request.getSession()); - i.eval(script); - - a = (Action) i.get("action"); - - if (a != null) { - return a; - } - - } catch (EvalError e) { - log(request, "Error running custom beanshell rule (" + id + ") - " + e.getMessage()); - } - - return new DoNothingAction(); - } - - private String getFileContents(File f) throws IOException { - StringBuffer sb = new StringBuffer(); - BufferedReader br = null; - - try { - br = new BufferedReader(new FileReader(f)); - String line; - while ((line = br.readLine()) != null) { - sb.append(line + System.getProperty("line.separator")); - } - - } finally { - if (br != null) { - br.close(); - } - } - return sb.toString(); - } + private Interpreter i; + private String script; + private Pattern path; + + public BeanShellRule(String fileLocation, String id, Pattern path) throws IOException, EvalError { + i = new Interpreter(); + i.set("logger", logger); + this.script = getFileContents(ESAPI.securityConfiguration().getResourceFile(fileLocation)); + this.id = id; + this.path = path; + } + + public Action check(HttpServletRequest request, InterceptingHTTPServletResponse response, + HttpServletResponse httpResponse) { + + /* + * Early fail: if the URL doesn't match one we're interested in. + */ + + if (path != null && !path.matcher(request.getRequestURI()).matches()) { + return new DoNothingAction(); + } + + /* + * Run the beanshell that we've already parsed and pre-compiled. + * Populate the "request" and "response" objects so the script has + * access to the same variables we do here. + */ + + try { + + Action a = null; + + i.set("action", a); + i.set("request", request); + + if (response != null) { + i.set("response", response); + } else { + i.set("response", httpResponse); + } + + i.set("session", request.getSession()); + i.eval(script); + + a = (Action) i.get("action"); + + if (a != null) { + return a; + } + + } catch (EvalError e) { + log(request, "Error running custom beanshell rule (" + id + ") - " + e.getMessage()); + } + + return new DoNothingAction(); + } + + private String getFileContents(File f) throws IOException { + StringBuffer sb = new StringBuffer(); + BufferedReader br = null; + + try { + br = new BufferedReader(new FileReader(f)); + String line; + while ((line = br.readLine()) != null) { + sb.append(line + System.getProperty("line.separator")); + } + + } finally { + if (br != null) { + br.close(); + } + } + return sb.toString(); + } } diff --git a/src/main/java/org/owasp/esapi/waf/rules/DetectOutboundContentRule.java b/src/main/java/org/owasp/esapi/waf/rules/DetectOutboundContentRule.java index d4f68f549..2a9388ffc 100644 --- a/src/main/java/org/owasp/esapi/waf/rules/DetectOutboundContentRule.java +++ b/src/main/java/org/owasp/esapi/waf/rules/DetectOutboundContentRule.java @@ -35,82 +35,82 @@ */ public class DetectOutboundContentRule extends Rule { - private Pattern contentType; - private Pattern pattern; - private Pattern uri; - - public DetectOutboundContentRule(String id, Pattern contentType, Pattern pattern, Pattern uri) { - this.contentType = contentType; - this.pattern = pattern; - this.uri = uri; - setId(id); - } - - public Action check(HttpServletRequest request, - InterceptingHTTPServletResponse response, - HttpServletResponse httpResponse) { - - /* - * Early fail: if URI doesn't match. - */ - if ( uri != null && ! uri.matcher(request.getRequestURI()).matches() ) { - return new DoNothingAction(); - } - - /* - * Early fail: if the content type is one we'd like to search for output patterns. - */ - - String inboundContentType; - String charEnc; - - if ( response != null ) { - if ( response.getContentType() == null ) { - response.setContentType(AppGuardianConfiguration.DEFAULT_CONTENT_TYPE); - } - inboundContentType = response.getContentType(); - charEnc = response.getCharacterEncoding(); - - } else { - if ( httpResponse.getContentType() == null ) { - httpResponse.setContentType(AppGuardianConfiguration.DEFAULT_CONTENT_TYPE); - } - inboundContentType = httpResponse.getContentType(); - charEnc = httpResponse.getCharacterEncoding(); - } - - if ( contentType.matcher(inboundContentType).matches() ) { - /* - * Depending on the encoding, search through the bytes - * for the pattern. - */ - try { - - byte[] bytes = null; - - try { - bytes = response.getInterceptingServletOutputStream().getResponseBytes(); - } catch (IOException ioe) { - log(request,"Error matching pattern '" + pattern.pattern() + "', IOException encountered (possibly too large?): " + ioe.getMessage() + " (in response to URL: '" + request.getRequestURL() + "')"); - return new DoNothingAction(); // yes this is a fail open! - } - - String s = new String(bytes,charEnc); - - if ( pattern.matcher(s).matches() ) { - - log(request,"Content pattern '" + pattern.pattern() + "' was found in response to URL: '" + request.getRequestURL() + "'"); - return new DefaultAction(); - - } - - } catch (UnsupportedEncodingException uee) { - log(request,"Content pattern '" + pattern.pattern() + "' could not be found due to encoding error: " + uee.getMessage()); - } - } - - return new DoNothingAction(); - - } + private Pattern contentType; + private Pattern pattern; + private Pattern uri; + + public DetectOutboundContentRule(String id, Pattern contentType, Pattern pattern, Pattern uri) { + this.contentType = contentType; + this.pattern = pattern; + this.uri = uri; + setId(id); + } + + public Action check(HttpServletRequest request, + InterceptingHTTPServletResponse response, + HttpServletResponse httpResponse) { + + /* + * Early fail: if URI doesn't match. + */ + if ( uri != null && ! uri.matcher(request.getRequestURI()).matches() ) { + return new DoNothingAction(); + } + + /* + * Early fail: if the content type is one we'd like to search for output patterns. + */ + + String inboundContentType; + String charEnc; + + if ( response != null ) { + if ( response.getContentType() == null ) { + response.setContentType(AppGuardianConfiguration.DEFAULT_CONTENT_TYPE); + } + inboundContentType = response.getContentType(); + charEnc = response.getCharacterEncoding(); + + } else { + if ( httpResponse.getContentType() == null ) { + httpResponse.setContentType(AppGuardianConfiguration.DEFAULT_CONTENT_TYPE); + } + inboundContentType = httpResponse.getContentType(); + charEnc = httpResponse.getCharacterEncoding(); + } + + if ( contentType.matcher(inboundContentType).matches() ) { + /* + * Depending on the encoding, search through the bytes + * for the pattern. + */ + try { + + byte[] bytes = null; + + try { + bytes = response.getInterceptingServletOutputStream().getResponseBytes(); + } catch (IOException ioe) { + log(request,"Error matching pattern '" + pattern.pattern() + "', IOException encountered (possibly too large?): " + ioe.getMessage() + " (in response to URL: '" + request.getRequestURL() + "')"); + return new DoNothingAction(); // yes this is a fail open! + } + + String s = new String(bytes,charEnc); + + if ( pattern.matcher(s).matches() ) { + + log(request,"Content pattern '" + pattern.pattern() + "' was found in response to URL: '" + request.getRequestURL() + "'"); + return new DefaultAction(); + + } + + } catch (UnsupportedEncodingException uee) { + log(request,"Content pattern '" + pattern.pattern() + "' could not be found due to encoding error: " + uee.getMessage()); + } + } + + return new DoNothingAction(); + + } } diff --git a/src/main/java/org/owasp/esapi/waf/rules/EnforceHTTPSRule.java b/src/main/java/org/owasp/esapi/waf/rules/EnforceHTTPSRule.java index d15875580..8b8cb441d 100644 --- a/src/main/java/org/owasp/esapi/waf/rules/EnforceHTTPSRule.java +++ b/src/main/java/org/owasp/esapi/waf/rules/EnforceHTTPSRule.java @@ -35,61 +35,61 @@ */ public class EnforceHTTPSRule extends Rule { - private Pattern path; - private List exceptions; - private String action; + private Pattern path; + private List exceptions; + private String action; - /* - * action = [ redirect | block ] [=default (redirect will redirect to error page] - */ + /* + * action = [ redirect | block ] [=default (redirect will redirect to error page] + */ - public EnforceHTTPSRule(String id, Pattern path, List exceptions, String action) { - this.path = path; - this.exceptions = exceptions; - this.action = action; - setId(id); - } + public EnforceHTTPSRule(String id, Pattern path, List exceptions, String action) { + this.path = path; + this.exceptions = exceptions; + this.action = action; + setId(id); + } - public Action check(HttpServletRequest request, - InterceptingHTTPServletResponse response, - HttpServletResponse httpResponse) { + public Action check(HttpServletRequest request, + InterceptingHTTPServletResponse response, + HttpServletResponse httpResponse) { - if ( ! request.isSecure() ) { + if ( ! request.isSecure() ) { - if ( path.matcher(request.getRequestURI()).matches() ) { + if ( path.matcher(request.getRequestURI()).matches() ) { - Iterator it = exceptions.iterator(); + Iterator it = exceptions.iterator(); - while(it.hasNext()){ + while(it.hasNext()){ - Object o = it.next(); + Object o = it.next(); - if ( o instanceof String ) { - if ( ((String)o).equalsIgnoreCase(request.getRequestURI()) ) { - return new DoNothingAction(); - } - } else if ( o instanceof Pattern ) { - if ( ((Pattern)o).matcher(request.getRequestURI()).matches() ) { - return new DoNothingAction(); - } - } + if ( o instanceof String ) { + if ( ((String)o).equalsIgnoreCase(request.getRequestURI()) ) { + return new DoNothingAction(); + } + } else if ( o instanceof Pattern ) { + if ( ((Pattern)o).matcher(request.getRequestURI()).matches() ) { + return new DoNothingAction(); + } + } - } + } - log(request,"Insecure request to resource detected in URL: '" + request.getRequestURL() + "'"); + log(request,"Insecure request to resource detected in URL: '" + request.getRequestURL() + "'"); - if ( "redirect".equals(action) ) { - RedirectAction ra = new RedirectAction(); - ra.setRedirectURL(request.getRequestURL().toString().replaceFirst("http", "https")); - return ra; - } + if ( "redirect".equals(action) ) { + RedirectAction ra = new RedirectAction(); + ra.setRedirectURL(request.getRequestURL().toString().replaceFirst("http", "https")); + return ra; + } - return new DefaultAction(); + return new DefaultAction(); - } - } + } + } - return new DoNothingAction(); + return new DoNothingAction(); - } + } } diff --git a/src/main/java/org/owasp/esapi/waf/rules/GeneralAttackSignatureRule.java b/src/main/java/org/owasp/esapi/waf/rules/GeneralAttackSignatureRule.java index 56fad6c19..d427abda1 100644 --- a/src/main/java/org/owasp/esapi/waf/rules/GeneralAttackSignatureRule.java +++ b/src/main/java/org/owasp/esapi/waf/rules/GeneralAttackSignatureRule.java @@ -35,29 +35,29 @@ */ public class GeneralAttackSignatureRule extends Rule { - private Pattern signature; - - public GeneralAttackSignatureRule(String id, Pattern signature) { - this.signature = signature; - setId(id); - } - - public Action check(HttpServletRequest req, - InterceptingHTTPServletResponse response, - HttpServletResponse httpResponse) { - - InterceptingHTTPServletRequest request = (InterceptingHTTPServletRequest)req; - Enumeration e = request.getParameterNames(); - - while(e.hasMoreElements()) { - String param = (String)e.nextElement(); - if ( signature.matcher(request.getDictionaryParameter(param)).matches() ) { - log(request,"General attack signature detected in parameter '" + param + "' value '" + request.getDictionaryParameter(param) + "'"); - return new DefaultAction(); - } - } - - return new DoNothingAction(); - } + private Pattern signature; + + public GeneralAttackSignatureRule(String id, Pattern signature) { + this.signature = signature; + setId(id); + } + + public Action check(HttpServletRequest req, + InterceptingHTTPServletResponse response, + HttpServletResponse httpResponse) { + + InterceptingHTTPServletRequest request = (InterceptingHTTPServletRequest)req; + Enumeration e = request.getParameterNames(); + + while(e.hasMoreElements()) { + String param = (String)e.nextElement(); + if ( signature.matcher(request.getDictionaryParameter(param)).matches() ) { + log(request,"General attack signature detected in parameter '" + param + "' value '" + request.getDictionaryParameter(param) + "'"); + return new DefaultAction(); + } + } + + return new DoNothingAction(); + } } diff --git a/src/main/java/org/owasp/esapi/waf/rules/HTTPMethodRule.java b/src/main/java/org/owasp/esapi/waf/rules/HTTPMethodRule.java index cd9e603a1..eecbcbfe2 100644 --- a/src/main/java/org/owasp/esapi/waf/rules/HTTPMethodRule.java +++ b/src/main/java/org/owasp/esapi/waf/rules/HTTPMethodRule.java @@ -32,47 +32,47 @@ */ public class HTTPMethodRule extends Rule { - private Pattern allowedMethods; - private Pattern deniedMethods; - private Pattern path; + private Pattern allowedMethods; + private Pattern deniedMethods; + private Pattern path; - public HTTPMethodRule(String id, Pattern allowedMethods, Pattern deniedMethods, Pattern path) { - this.allowedMethods = allowedMethods; - this.deniedMethods = deniedMethods; - this.path = path; - setId(id); - } + public HTTPMethodRule(String id, Pattern allowedMethods, Pattern deniedMethods, Pattern path) { + this.allowedMethods = allowedMethods; + this.deniedMethods = deniedMethods; + this.path = path; + setId(id); + } - public Action check(HttpServletRequest request, - InterceptingHTTPServletResponse response, - HttpServletResponse httpResponse) { + public Action check(HttpServletRequest request, + InterceptingHTTPServletResponse response, + HttpServletResponse httpResponse) { - /* - * If no path is specified, apply rule globally. - */ - String uri = request.getRequestURI(); - String method = request.getMethod(); + /* + * If no path is specified, apply rule globally. + */ + String uri = request.getRequestURI(); + String method = request.getMethod(); - if ( path == null || path.matcher(uri).matches() ) { - /* - * Order allow, deny. - */ + if ( path == null || path.matcher(uri).matches() ) { + /* + * Order allow, deny. + */ - if ( allowedMethods != null && allowedMethods.matcher(method).matches() ) { - return new DoNothingAction(); - } else if ( allowedMethods != null ) { - log(request,"Disallowed HTTP method '" + request.getMethod() + "' found for URL: " + request.getRequestURL()); - return new DefaultAction(); - } + if ( allowedMethods != null && allowedMethods.matcher(method).matches() ) { + return new DoNothingAction(); + } else if ( allowedMethods != null ) { + log(request,"Disallowed HTTP method '" + request.getMethod() + "' found for URL: " + request.getRequestURL()); + return new DefaultAction(); + } - if ( deniedMethods != null && deniedMethods.matcher(method).matches() ) { - log(request,"Disallowed HTTP method '" + request.getMethod() + "' found for URL: " + request.getRequestURL()); - return new DefaultAction(); - } + if ( deniedMethods != null && deniedMethods.matcher(method).matches() ) { + log(request,"Disallowed HTTP method '" + request.getMethod() + "' found for URL: " + request.getRequestURL()); + return new DefaultAction(); + } - } + } - return new DoNothingAction(); - } + return new DoNothingAction(); + } } diff --git a/src/main/java/org/owasp/esapi/waf/rules/IPRule.java b/src/main/java/org/owasp/esapi/waf/rules/IPRule.java index 3381afe05..3308ced68 100644 --- a/src/main/java/org/owasp/esapi/waf/rules/IPRule.java +++ b/src/main/java/org/owasp/esapi/waf/rules/IPRule.java @@ -32,48 +32,48 @@ */ public class IPRule extends Rule { - private Pattern allowedIP; - private String exactPath; - private Pattern path; - private boolean useExactPath = false; - private String ipHeader; + private Pattern allowedIP; + private String exactPath; + private Pattern path; + private boolean useExactPath = false; + private String ipHeader; - public IPRule(String id, Pattern allowedIP, Pattern path, String ipHeader) { - this.allowedIP = allowedIP; - this.path = path; - this.useExactPath = false; - this.ipHeader = ipHeader; - setId(id); - } + public IPRule(String id, Pattern allowedIP, Pattern path, String ipHeader) { + this.allowedIP = allowedIP; + this.path = path; + this.useExactPath = false; + this.ipHeader = ipHeader; + setId(id); + } - public IPRule(String id, Pattern allowedIP, String exactPath) { - this.path = null; - this.exactPath = exactPath; - this.useExactPath = true; - setId(id); - } + public IPRule(String id, Pattern allowedIP, String exactPath) { + this.path = null; + this.exactPath = exactPath; + this.useExactPath = true; + setId(id); + } - public Action check(HttpServletRequest request, - InterceptingHTTPServletResponse response, - HttpServletResponse httpResponse) { + public Action check(HttpServletRequest request, + InterceptingHTTPServletResponse response, + HttpServletResponse httpResponse) { - String uri = request.getRequestURI(); + String uri = request.getRequestURI(); - if ( (!useExactPath && path.matcher(uri).matches()) || - ( useExactPath && exactPath.equals(uri)) ) { - - String sourceIP = request.getRemoteAddr() + ""; - - if ( ipHeader != null ) { - sourceIP = request.getHeader(ipHeader); - } - - if ( ! allowedIP.matcher(sourceIP).matches() ) { - log(request, "IP not allowed to access URI '" + uri + "'"); - return new DefaultAction(); - } - } + if ( (!useExactPath && path.matcher(uri).matches()) || + ( useExactPath && exactPath.equals(uri)) ) { + + String sourceIP = request.getRemoteAddr() + ""; + + if ( ipHeader != null ) { + sourceIP = request.getHeader(ipHeader); + } + + if ( ! allowedIP.matcher(sourceIP).matches() ) { + log(request, "IP not allowed to access URI '" + uri + "'"); + return new DefaultAction(); + } + } - return new DoNothingAction(); - } + return new DoNothingAction(); + } } diff --git a/src/main/java/org/owasp/esapi/waf/rules/MustMatchRule.java b/src/main/java/org/owasp/esapi/waf/rules/MustMatchRule.java index b761e2358..7c12f2ccd 100644 --- a/src/main/java/org/owasp/esapi/waf/rules/MustMatchRule.java +++ b/src/main/java/org/owasp/esapi/waf/rules/MustMatchRule.java @@ -37,300 +37,300 @@ */ public class MustMatchRule extends Rule { - private static final String REQUEST_PARAMETERS = "request.parameters."; - private static final String REQUEST_HEADERS = "request.headers."; - private static final String REQUEST_URI = "request.uri"; - private static final String REQUEST_URL = "request.url"; - private static final String SESSION_ATTRIBUTES = "session."; + private static final String REQUEST_PARAMETERS = "request.parameters."; + private static final String REQUEST_HEADERS = "request.headers."; + private static final String REQUEST_URI = "request.uri"; + private static final String REQUEST_URL = "request.url"; + private static final String SESSION_ATTRIBUTES = "session."; - private Pattern path; - private String variable; - private int operator; - private String value; + private Pattern path; + private String variable; + private int operator; + private String value; - public MustMatchRule(String id, Pattern path, String variable, int operator, String value) { - this.path = path; - this.variable = variable; - this.operator = operator; - this.value = value; - setId(id); - } + public MustMatchRule(String id, Pattern path, String variable, int operator, String value) { + this.path = path; + this.variable = variable; + this.operator = operator; + this.value = value; + setId(id); + } - public Action check(HttpServletRequest req, - InterceptingHTTPServletResponse response, - HttpServletResponse httpResponse) { + public Action check(HttpServletRequest req, + InterceptingHTTPServletResponse response, + HttpServletResponse httpResponse) { - InterceptingHTTPServletRequest request = (InterceptingHTTPServletRequest)req; + InterceptingHTTPServletRequest request = (InterceptingHTTPServletRequest)req; - String uri = request.getRequestURI(); - if ( ! path.matcher(uri).matches() ) { + String uri = request.getRequestURI(); + if ( ! path.matcher(uri).matches() ) { - return new DoNothingAction(); + return new DoNothingAction(); - } else { + } else { - String target = null; + String target = null; - /* - * First check if we're going to be dealing with request parameters - */ - if ( variable.startsWith( REQUEST_PARAMETERS ) ) { + /* + * First check if we're going to be dealing with request parameters + */ + if ( variable.startsWith( REQUEST_PARAMETERS ) ) { - if ( operator == AppGuardianConfiguration.OPERATOR_EXISTS ) { + if ( operator == AppGuardianConfiguration.OPERATOR_EXISTS ) { - target = variable.substring(REQUEST_PARAMETERS.length()); + target = variable.substring(REQUEST_PARAMETERS.length()); - if ( request.getParameter(target) != null ) { - return new DoNothingAction(); - } + if ( request.getParameter(target) != null ) { + return new DoNothingAction(); + } - } else if ( operator == AppGuardianConfiguration.OPERATOR_IN_LIST ) { + } else if ( operator == AppGuardianConfiguration.OPERATOR_IN_LIST ) { - /* - * This doesn't make sense. The variable to test is a request parameter - * but the rule is looking for a List. Let the control fall through - * to the bottom where we'll return false. - */ + /* + * This doesn't make sense. The variable to test is a request parameter + * but the rule is looking for a List. Let the control fall through + * to the bottom where we'll return false. + */ - } else if ( operator == AppGuardianConfiguration.OPERATOR_EQ || operator == AppGuardianConfiguration.OPERATOR_CONTAINS ) { + } else if ( operator == AppGuardianConfiguration.OPERATOR_EQ || operator == AppGuardianConfiguration.OPERATOR_CONTAINS ) { - /** - * Working with request parameters. If we detect - * simple regex characters, we treat it as a regex. - * Otherwise we treat it as a single parameter. - */ - target = variable.substring(REQUEST_PARAMETERS.length()); + /** + * Working with request parameters. If we detect + * simple regex characters, we treat it as a regex. + * Otherwise we treat it as a single parameter. + */ + target = variable.substring(REQUEST_PARAMETERS.length()); - if ( target.contains("*") || target.contains("?") ) { + if ( target.contains("*") || target.contains("?") ) { - target = target.replaceAll("*", ".*"); - Pattern p = Pattern.compile(target); + target = target.replaceAll("*", ".*"); + Pattern p = Pattern.compile(target); - Enumeration e = request.getParameterNames(); + Enumeration e = request.getParameterNames(); - while(e.hasMoreElements()) { - String param = (String)e.nextElement(); + while(e.hasMoreElements()) { + String param = (String)e.nextElement(); - if ( p.matcher(param).matches() ) { - String s = request.getParameter(param); - if ( ! RuleUtil.testValue(s, value, operator) ) { - log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', input='" + s + "' parameter='"+param+"'"); - return new DefaultAction(); - } - } - } + if ( p.matcher(param).matches() ) { + String s = request.getParameter(param); + if ( ! RuleUtil.testValue(s, value, operator) ) { + log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', input='" + s + "' parameter='"+param+"'"); + return new DefaultAction(); + } + } + } - } else { + } else { - String s = request.getParameter(target); + String s = request.getParameter(target); - if ( ! RuleUtil.testValue(s, value, operator) ) { - log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', input='" + s + "', parameter='"+target+"'"); - return new DefaultAction(); - } + if ( ! RuleUtil.testValue(s, value, operator) ) { + log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', input='" + s + "', parameter='"+target+"'"); + return new DefaultAction(); + } - } - } + } + } - } else if ( variable.startsWith( REQUEST_HEADERS ) ) { + } else if ( variable.startsWith( REQUEST_HEADERS ) ) { - /** - * Do the same for request headers. - */ + /** + * Do the same for request headers. + */ - if ( operator == AppGuardianConfiguration.OPERATOR_EXISTS ) { + if ( operator == AppGuardianConfiguration.OPERATOR_EXISTS ) { - target = variable.substring(REQUEST_HEADERS.length()); + target = variable.substring(REQUEST_HEADERS.length()); - if ( request.getHeader(target) != null ) { - return new DoNothingAction(); - } + if ( request.getHeader(target) != null ) { + return new DoNothingAction(); + } - } else if ( operator == AppGuardianConfiguration.OPERATOR_IN_LIST ) { + } else if ( operator == AppGuardianConfiguration.OPERATOR_IN_LIST ) { - /* - * This doesn't make sense. The variable to test is a request header - * but the rule is looking for a List. Let the control fall through - * to the bottom where we'll return false. - */ + /* + * This doesn't make sense. The variable to test is a request header + * but the rule is looking for a List. Let the control fall through + * to the bottom where we'll return false. + */ - } else if ( operator == AppGuardianConfiguration.OPERATOR_EQ || operator == AppGuardianConfiguration.OPERATOR_CONTAINS ) { + } else if ( operator == AppGuardianConfiguration.OPERATOR_EQ || operator == AppGuardianConfiguration.OPERATOR_CONTAINS ) { - target = variable.substring(REQUEST_HEADERS.length()); + target = variable.substring(REQUEST_HEADERS.length()); - if ( target.contains("*") || target.contains("?") ) { + if ( target.contains("*") || target.contains("?") ) { - target = target.replaceAll("*", ".*"); - Pattern p = Pattern.compile(target); + target = target.replaceAll("*", ".*"); + Pattern p = Pattern.compile(target); - Enumeration e = request.getHeaderNames(); + Enumeration e = request.getHeaderNames(); - while(e.hasMoreElements()) { - String header = (String)e.nextElement(); - if ( p.matcher(header).matches() ) { - String s = request.getHeader(header); - if ( ! RuleUtil.testValue(s, value, operator) ) { - log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', input='" + s + "', header='"+header+"'"); - return new DefaultAction(); - } - } - } + while(e.hasMoreElements()) { + String header = (String)e.nextElement(); + if ( p.matcher(header).matches() ) { + String s = request.getHeader(header); + if ( ! RuleUtil.testValue(s, value, operator) ) { + log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', input='" + s + "', header='"+header+"'"); + return new DefaultAction(); + } + } + } - return new DoNothingAction(); + return new DoNothingAction(); - } else { + } else { - String s = request.getHeader(target); + String s = request.getHeader(target); - if ( s == null || ! RuleUtil.testValue(s, value, operator) ) { - log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', input='" + s + "', header='"+target+"'"); - return new DefaultAction(); - } + if ( s == null || ! RuleUtil.testValue(s, value, operator) ) { + log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', input='" + s + "', header='"+target+"'"); + return new DefaultAction(); + } - return new DoNothingAction(); + return new DoNothingAction(); - } + } - } + } - } else if ( variable.startsWith(SESSION_ATTRIBUTES) ) { + } else if ( variable.startsWith(SESSION_ATTRIBUTES) ) { - /** - * Do the same for session attributes. Can't possibly match - * ANY rule if there is no session object. - */ - if ( request.getSession(false) == null ) { - return new DefaultAction(); - } + /** + * Do the same for session attributes. Can't possibly match + * ANY rule if there is no session object. + */ + if ( request.getSession(false) == null ) { + return new DefaultAction(); + } - target = variable.substring(SESSION_ATTRIBUTES.length()+1); + target = variable.substring(SESSION_ATTRIBUTES.length()+1); - if ( operator == AppGuardianConfiguration.OPERATOR_IN_LIST ) { + if ( operator == AppGuardianConfiguration.OPERATOR_IN_LIST ) { - /* - * Want to check if the List/Enumeration/whatever stored - * in "target" contains the value in "value". - */ + /* + * Want to check if the List/Enumeration/whatever stored + * in "target" contains the value in "value". + */ - Object o = request.getSession(false).getAttribute(target); + Object o = request.getSession(false).getAttribute(target); - if ( o instanceof Collection ) { - if ( RuleUtil.isInList((Collection)o, value) ) { - return new DoNothingAction(); - } else { - log(request, "MustMatch rule failed - looking for value='" + value + "', in session Collection attribute '" + target + "']"); - return new DefaultAction(); - } - } else if ( o instanceof Map ) { - if ( RuleUtil.isInList((Map)o, value) ) { - return new DoNothingAction(); - } else { - log(request, "MustMatch rule failed - looking for value='" + value + "', in session Map attribute '" + target + "']"); - return new DefaultAction(); - } - } else if ( o instanceof Enumeration ) { - if ( RuleUtil.isInList((Enumeration)o, value) ) { - return new DoNothingAction(); - } else { - log(request, "MustMatch rule failed - looking for value='" + value + "', in session Enumeration attribute '" + target + "']"); - return new DefaultAction(); - } - } + if ( o instanceof Collection ) { + if ( RuleUtil.isInList((Collection)o, value) ) { + return new DoNothingAction(); + } else { + log(request, "MustMatch rule failed - looking for value='" + value + "', in session Collection attribute '" + target + "']"); + return new DefaultAction(); + } + } else if ( o instanceof Map ) { + if ( RuleUtil.isInList((Map)o, value) ) { + return new DoNothingAction(); + } else { + log(request, "MustMatch rule failed - looking for value='" + value + "', in session Map attribute '" + target + "']"); + return new DefaultAction(); + } + } else if ( o instanceof Enumeration ) { + if ( RuleUtil.isInList((Enumeration)o, value) ) { + return new DoNothingAction(); + } else { + log(request, "MustMatch rule failed - looking for value='" + value + "', in session Enumeration attribute '" + target + "']"); + return new DefaultAction(); + } + } - /* - * The attribute was not a common list-type of Java object s - * let the control fall through to the bottom where it will - * fail. - */ + /* + * The attribute was not a common list-type of Java object s + * let the control fall through to the bottom where it will + * fail. + */ - } else if ( operator == AppGuardianConfiguration.OPERATOR_EXISTS) { + } else if ( operator == AppGuardianConfiguration.OPERATOR_EXISTS) { - Object o = request.getSession(false).getAttribute(target); + Object o = request.getSession(false).getAttribute(target); - if ( o != null ) { - return new DoNothingAction(); - } else { - log(request, "MustMatch rule failed - couldn't find required session attribute='" + target + "'"); - return new DefaultAction(); - } + if ( o != null ) { + return new DoNothingAction(); + } else { + log(request, "MustMatch rule failed - couldn't find required session attribute='" + target + "'"); + return new DefaultAction(); + } - } else if ( operator == AppGuardianConfiguration.OPERATOR_EQ || operator == AppGuardianConfiguration.OPERATOR_CONTAINS ) { + } else if ( operator == AppGuardianConfiguration.OPERATOR_EQ || operator == AppGuardianConfiguration.OPERATOR_CONTAINS ) { - if ( target.contains("*") || target.contains("?") ) { + if ( target.contains("*") || target.contains("?") ) { - target = target.replaceAll("\\*", ".*"); - Pattern p = Pattern.compile(target); + target = target.replaceAll("\\*", ".*"); + Pattern p = Pattern.compile(target); - Enumeration e = request.getSession(false).getAttributeNames(); + Enumeration e = request.getSession(false).getAttributeNames(); - while(e.hasMoreElements()) { + while(e.hasMoreElements()) { - String attr = (String)e.nextElement(); + String attr = (String)e.nextElement(); - if (p.matcher(attr).matches() ) { + if (p.matcher(attr).matches() ) { - Object o = request.getSession(false).getAttribute(attr); + Object o = request.getSession(false).getAttribute(attr); - if ( ! RuleUtil.testValue((String)o, value, operator) ) { - log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', session attribute='" + attr + "', attribute value='"+(String)o+"'"); - return new DefaultAction(); - } else { - return new DoNothingAction(); - } - } - } + if ( ! RuleUtil.testValue((String)o, value, operator) ) { + log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', session attribute='" + attr + "', attribute value='"+(String)o+"'"); + return new DefaultAction(); + } else { + return new DoNothingAction(); + } + } + } - } else { + } else { - Object o = request.getSession(false).getAttribute(target); + Object o = request.getSession(false).getAttribute(target); - if ( ! RuleUtil.testValue((String)o, value, operator) ) { - log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', session attribute='" + target + "', attribute value='"+(String)o+"'"); - return new DefaultAction(); - } else { - return new DoNothingAction(); - } + if ( ! RuleUtil.testValue((String)o, value, operator) ) { + log(request, "MustMatch rule failed (operator="+operator+"), value='" + value + "', session attribute='" + target + "', attribute value='"+(String)o+"'"); + return new DefaultAction(); + } else { + return new DoNothingAction(); + } - } - - } - - } else if ( variable.equals( REQUEST_URI ) ) { - - if ( operator == AppGuardianConfiguration.OPERATOR_EQ || operator == AppGuardianConfiguration.OPERATOR_CONTAINS ) { - if ( RuleUtil.testValue(request.getRequestURI(), value, operator) ) { - return new DoNothingAction(); - } else { - log(request, "MustMatch rule on request URI failed (operator="+operator+"), requestURI='" + request.getRequestURI() + "', value='" + value+ "'"); - return new DefaultAction(); - } - } - - /* - * Any other operator doesn't make sense. - */ - - } else if ( variable.equals( REQUEST_URL ) ) { - - if ( operator == AppGuardianConfiguration.OPERATOR_EQ || operator == AppGuardianConfiguration.OPERATOR_CONTAINS ) { - if ( RuleUtil.testValue(request.getRequestURL().toString(), value, operator) ) { - return new DoNothingAction(); - } else { - log(request, "MustMatch rule on request URL failed (operator="+operator+"), requestURL='" + request.getRequestURL() + "', value='" + value+ "'"); - return new DefaultAction(); - } - } - - /* - * Any other operator doesn't make sense. - */ - } + } + + } + + } else if ( variable.equals( REQUEST_URI ) ) { + + if ( operator == AppGuardianConfiguration.OPERATOR_EQ || operator == AppGuardianConfiguration.OPERATOR_CONTAINS ) { + if ( RuleUtil.testValue(request.getRequestURI(), value, operator) ) { + return new DoNothingAction(); + } else { + log(request, "MustMatch rule on request URI failed (operator="+operator+"), requestURI='" + request.getRequestURI() + "', value='" + value+ "'"); + return new DefaultAction(); + } + } + + /* + * Any other operator doesn't make sense. + */ + + } else if ( variable.equals( REQUEST_URL ) ) { + + if ( operator == AppGuardianConfiguration.OPERATOR_EQ || operator == AppGuardianConfiguration.OPERATOR_CONTAINS ) { + if ( RuleUtil.testValue(request.getRequestURL().toString(), value, operator) ) { + return new DoNothingAction(); + } else { + log(request, "MustMatch rule on request URL failed (operator="+operator+"), requestURL='" + request.getRequestURL() + "', value='" + value+ "'"); + return new DefaultAction(); + } + } + + /* + * Any other operator doesn't make sense. + */ + } - } + } - log(request, "MustMatch rule failed close on URL '" + request.getRequestURL() + "'"); - return new DefaultAction(); + log(request, "MustMatch rule failed close on URL '" + request.getRequestURL() + "'"); + return new DefaultAction(); - } + } } diff --git a/src/main/java/org/owasp/esapi/waf/rules/PathExtensionRule.java b/src/main/java/org/owasp/esapi/waf/rules/PathExtensionRule.java index 06b13e2fd..9c61eabd9 100644 --- a/src/main/java/org/owasp/esapi/waf/rules/PathExtensionRule.java +++ b/src/main/java/org/owasp/esapi/waf/rules/PathExtensionRule.java @@ -32,29 +32,29 @@ */ public class PathExtensionRule extends Rule { - private Pattern allow; - private Pattern deny; + private Pattern allow; + private Pattern deny; - public PathExtensionRule (String id, Pattern allow, Pattern deny) { - this.allow = allow; - this.deny = deny; - setId(id); - } + public PathExtensionRule (String id, Pattern allow, Pattern deny) { + this.allow = allow; + this.deny = deny; + setId(id); + } - public Action check(HttpServletRequest request, - InterceptingHTTPServletResponse response, - HttpServletResponse httpResponse) { + public Action check(HttpServletRequest request, + InterceptingHTTPServletResponse response, + HttpServletResponse httpResponse) { - if ( allow != null && allow.matcher(request.getRequestURI()).matches() ) { - return new DoNothingAction(); - } else if ( deny != null && deny.matcher(request.getRequestURI()).matches() ) { + if ( allow != null && allow.matcher(request.getRequestURI()).matches() ) { + return new DoNothingAction(); + } else if ( deny != null && deny.matcher(request.getRequestURI()).matches() ) { - log(request, "Disallowed extension pattern '" + deny.pattern() + "' found on URI '" + request.getRequestURI() + "'"); + log(request, "Disallowed extension pattern '" + deny.pattern() + "' found on URI '" + request.getRequestURI() + "'"); - return new DefaultAction(); - } + return new DefaultAction(); + } - return new DoNothingAction(); - } + return new DoNothingAction(); + } } diff --git a/src/main/java/org/owasp/esapi/waf/rules/ReplaceContentRule.java b/src/main/java/org/owasp/esapi/waf/rules/ReplaceContentRule.java index fd308ccac..4c8298401 100644 --- a/src/main/java/org/owasp/esapi/waf/rules/ReplaceContentRule.java +++ b/src/main/java/org/owasp/esapi/waf/rules/ReplaceContentRule.java @@ -36,78 +36,78 @@ */ public class ReplaceContentRule extends Rule { - private Pattern pattern; - private String replacement; - private Pattern contentType; - private Pattern path; - - public ReplaceContentRule(String id, Pattern pattern, String replacement, Pattern contentType, Pattern path) { - this.pattern = pattern; - this.replacement = replacement; - this.path = path; - this.contentType = contentType; - setId(id); - } - - /* - * Use regular expressions with capturing parentheses to perform replacement. - */ - - public Action check(HttpServletRequest request, - InterceptingHTTPServletResponse response, - HttpServletResponse httpResponse) { - - /* - * First early fail: if the URI doesn't match the paths we're interested in. - */ - String uri = request.getRequestURI(); - if ( path != null && ! path.matcher(uri).matches() ) { - return new DoNothingAction(); - } - - /* - * Second early fail: if the content type is one we'd like to search for output patterns. - */ - - if ( contentType != null ) { - if ( response.getContentType() != null && ! contentType.matcher(response.getContentType()).matches() ) { - return new DoNothingAction(); - } - } - - byte[] bytes = null; - - try { - bytes = response.getInterceptingServletOutputStream().getResponseBytes(); - } catch (IOException ioe) { - log(request,"Error matching pattern '" + pattern.pattern() + "', IOException encountered (possibly too large?): " + ioe.getMessage() + " (in response to URL: '" + request.getRequestURL() + "')"); - return new DoNothingAction(); // yes this is a fail open! - } - - - try { - - String s = new String(bytes,response.getCharacterEncoding()); - - Matcher m = pattern.matcher(s); - String canary = m.replaceAll(replacement); - - try { - - if ( ! s.equals(canary) ) { - response.getInterceptingServletOutputStream().setResponseBytes(canary.getBytes(response.getCharacterEncoding())); - logger.debug(Logger.SECURITY_SUCCESS, "Successfully replaced pattern '" + pattern.pattern() + "' on response to URL '" + request.getRequestURL() + "'"); - } - - } catch (IOException ioe) { - logger.error(Logger.SECURITY_FAILURE, "Failed to replace pattern '" + pattern.pattern() + "' on response to URL '" + request.getRequestURL() + "' due to [" + ioe.getMessage() + "]"); - } - - } catch(UnsupportedEncodingException uee) { - logger.error(Logger.SECURITY_FAILURE, "Failed to replace pattern '" + pattern.pattern() + "' on response to URL '" + request.getRequestURL() + "' due to [" + uee.getMessage() + "]"); - } - - return new DoNothingAction(); - } + private Pattern pattern; + private String replacement; + private Pattern contentType; + private Pattern path; + + public ReplaceContentRule(String id, Pattern pattern, String replacement, Pattern contentType, Pattern path) { + this.pattern = pattern; + this.replacement = replacement; + this.path = path; + this.contentType = contentType; + setId(id); + } + + /* + * Use regular expressions with capturing parentheses to perform replacement. + */ + + public Action check(HttpServletRequest request, + InterceptingHTTPServletResponse response, + HttpServletResponse httpResponse) { + + /* + * First early fail: if the URI doesn't match the paths we're interested in. + */ + String uri = request.getRequestURI(); + if ( path != null && ! path.matcher(uri).matches() ) { + return new DoNothingAction(); + } + + /* + * Second early fail: if the content type is one we'd like to search for output patterns. + */ + + if ( contentType != null ) { + if ( response.getContentType() != null && ! contentType.matcher(response.getContentType()).matches() ) { + return new DoNothingAction(); + } + } + + byte[] bytes = null; + + try { + bytes = response.getInterceptingServletOutputStream().getResponseBytes(); + } catch (IOException ioe) { + log(request,"Error matching pattern '" + pattern.pattern() + "', IOException encountered (possibly too large?): " + ioe.getMessage() + " (in response to URL: '" + request.getRequestURL() + "')"); + return new DoNothingAction(); // yes this is a fail open! + } + + + try { + + String s = new String(bytes,response.getCharacterEncoding()); + + Matcher m = pattern.matcher(s); + String canary = m.replaceAll(replacement); + + try { + + if ( ! s.equals(canary) ) { + response.getInterceptingServletOutputStream().setResponseBytes(canary.getBytes(response.getCharacterEncoding())); + logger.debug(Logger.SECURITY_SUCCESS, "Successfully replaced pattern '" + pattern.pattern() + "' on response to URL '" + request.getRequestURL() + "'"); + } + + } catch (IOException ioe) { + logger.error(Logger.SECURITY_FAILURE, "Failed to replace pattern '" + pattern.pattern() + "' on response to URL '" + request.getRequestURL() + "' due to [" + ioe.getMessage() + "]"); + } + + } catch(UnsupportedEncodingException uee) { + logger.error(Logger.SECURITY_FAILURE, "Failed to replace pattern '" + pattern.pattern() + "' on response to URL '" + request.getRequestURL() + "' due to [" + uee.getMessage() + "]"); + } + + return new DoNothingAction(); + } } diff --git a/src/main/java/org/owasp/esapi/waf/rules/RestrictContentTypeRule.java b/src/main/java/org/owasp/esapi/waf/rules/RestrictContentTypeRule.java index 298df3342..0891dfc5e 100644 --- a/src/main/java/org/owasp/esapi/waf/rules/RestrictContentTypeRule.java +++ b/src/main/java/org/owasp/esapi/waf/rules/RestrictContentTypeRule.java @@ -32,39 +32,39 @@ */ public class RestrictContentTypeRule extends Rule { - private Pattern allow; - private Pattern deny; + private Pattern allow; + private Pattern deny; - public RestrictContentTypeRule(String id, Pattern allow, Pattern deny) { - this.allow = allow; - this.deny = deny; - setId(id); - } + public RestrictContentTypeRule(String id, Pattern allow, Pattern deny) { + this.allow = allow; + this.deny = deny; + setId(id); + } - public Action check(HttpServletRequest request, - InterceptingHTTPServletResponse response, - HttpServletResponse httpResponse) { + public Action check(HttpServletRequest request, + InterceptingHTTPServletResponse response, + HttpServletResponse httpResponse) { - /* can't check content type if it's not available */ - if ( request.getContentType() == null ) { - return new DoNothingAction(); - } + /* can't check content type if it's not available */ + if ( request.getContentType() == null ) { + return new DoNothingAction(); + } - if ( allow != null ) { - if ( allow.matcher(request.getContentType()).matches() ) { - return new DoNothingAction(); - } - log(request, "Disallowed content type based on allow pattern '" + allow.pattern() + "' found on URI '" + request.getRequestURI() + "' (value was '" + request.getContentType() +"')"); - } else if ( deny != null ) { - if ( ! deny.matcher(request.getContentType()).matches() ) { - return new DoNothingAction(); - } - log(request, "Disallowed content type based on deny pattern '" + deny.pattern() + "' found on URI '" + request.getRequestURI() + "' (value was '" + request.getContentType() + ")'"); - } + if ( allow != null ) { + if ( allow.matcher(request.getContentType()).matches() ) { + return new DoNothingAction(); + } + log(request, "Disallowed content type based on allow pattern '" + allow.pattern() + "' found on URI '" + request.getRequestURI() + "' (value was '" + request.getContentType() +"')"); + } else if ( deny != null ) { + if ( ! deny.matcher(request.getContentType()).matches() ) { + return new DoNothingAction(); + } + log(request, "Disallowed content type based on deny pattern '" + deny.pattern() + "' found on URI '" + request.getRequestURI() + "' (value was '" + request.getContentType() + ")'"); + } - return new DefaultAction(); + return new DefaultAction(); - } + } } diff --git a/src/main/java/org/owasp/esapi/waf/rules/RestrictUserAgentRule.java b/src/main/java/org/owasp/esapi/waf/rules/RestrictUserAgentRule.java index 55988530b..204bde2c4 100644 --- a/src/main/java/org/owasp/esapi/waf/rules/RestrictUserAgentRule.java +++ b/src/main/java/org/owasp/esapi/waf/rules/RestrictUserAgentRule.java @@ -34,47 +34,47 @@ */ public class RestrictUserAgentRule extends Rule { - private static final String USER_AGENT_HEADER = "User-Agent"; + private static final String USER_AGENT_HEADER = "User-Agent"; - private Pattern allow; - private Pattern deny; + private Pattern allow; + private Pattern deny; - public RestrictUserAgentRule(String id, Pattern allow, Pattern deny) { - this.allow = allow; - this.deny = deny; - setId(id); - } + public RestrictUserAgentRule(String id, Pattern allow, Pattern deny) { + this.allow = allow; + this.deny = deny; + setId(id); + } - public Action check(HttpServletRequest request, InterceptingHTTPServletResponse response, HttpServletResponse httpResponse) { - - String userAgent = request.getHeader( USER_AGENT_HEADER ); - - if ( userAgent == null ) userAgent=""; - - if ( allow != null ) { - if ( allow.matcher(userAgent).matches() ) { - return new DoNothingAction(); - } - } else if ( deny != null ) { - if ( ! deny.matcher(userAgent).matches() ) { - return new DoNothingAction(); - } - } + public Action check(HttpServletRequest request, InterceptingHTTPServletResponse response, HttpServletResponse httpResponse) { + + String userAgent = request.getHeader( USER_AGENT_HEADER ); + + if ( userAgent == null ) userAgent=""; + + if ( allow != null ) { + if ( allow.matcher(userAgent).matches() ) { + return new DoNothingAction(); + } + } else if ( deny != null ) { + if ( ! deny.matcher(userAgent).matches() ) { + return new DoNothingAction(); + } + } - log(request, "Disallowed user agent pattern '" + deny.pattern() + "' found in user agent '" + request.getHeader(USER_AGENT_HEADER) + "'"); - - /* - * If we don't force this to "block", the user will be in an infinite loop, possibly - * eating our bandwidth, and in the case of a dread false positive, really piss them - * off. - * - * Better to just reject. - */ - if ( AppGuardianConfiguration.DEFAULT_FAIL_ACTION == AppGuardianConfiguration.REDIRECT ) { - return new BlockAction(); - } + log(request, "Disallowed user agent pattern '" + deny.pattern() + "' found in user agent '" + request.getHeader(USER_AGENT_HEADER) + "'"); + + /* + * If we don't force this to "block", the user will be in an infinite loop, possibly + * eating our bandwidth, and in the case of a dread false positive, really piss them + * off. + * + * Better to just reject. + */ + if ( AppGuardianConfiguration.DEFAULT_FAIL_ACTION == AppGuardianConfiguration.REDIRECT ) { + return new BlockAction(); + } - return new DefaultAction(); - } + return new DefaultAction(); + } } diff --git a/src/main/java/org/owasp/esapi/waf/rules/Rule.java b/src/main/java/org/owasp/esapi/waf/rules/Rule.java index c4773a514..8e1ee87a8 100644 --- a/src/main/java/org/owasp/esapi/waf/rules/Rule.java +++ b/src/main/java/org/owasp/esapi/waf/rules/Rule.java @@ -32,24 +32,24 @@ */ public abstract class Rule { - protected String id = "(no rule ID)"; - protected static Logger logger = ESAPI.getLogger(Rule.class); + protected String id = "(no rule ID)"; + protected static Logger logger = ESAPI.getLogger(Rule.class); - public abstract Action check( HttpServletRequest request, InterceptingHTTPServletResponse response, HttpServletResponse httpResponse ); + public abstract Action check( HttpServletRequest request, InterceptingHTTPServletResponse response, HttpServletResponse httpResponse ); - public void log( HttpServletRequest request, String message ) { - logger.warning(Logger.SECURITY_FAILURE,"[IP=" + request.getRemoteAddr() + - ",Rule=" + this.getClass().getSimpleName() + ",ID="+id+"] " + message); - } + public void log( HttpServletRequest request, String message ) { + logger.warning(Logger.SECURITY_FAILURE,"[IP=" + request.getRemoteAddr() + + ",Rule=" + this.getClass().getSimpleName() + ",ID="+id+"] " + message); + } - protected void setId(String id) { - if ( id == null || "".equals(id) ) - return; + protected void setId(String id) { + if ( id == null || "".equals(id) ) + return; - this.id = id; - } + this.id = id; + } - public String toString() { - return "Rule:" + this.getClass().getName(); - } + public String toString() { + return "Rule:" + this.getClass().getName(); + } } diff --git a/src/main/java/org/owasp/esapi/waf/rules/RuleUtil.java b/src/main/java/org/owasp/esapi/waf/rules/RuleUtil.java index 3213d1275..d8a43e1c7 100644 --- a/src/main/java/org/owasp/esapi/waf/rules/RuleUtil.java +++ b/src/main/java/org/owasp/esapi/waf/rules/RuleUtil.java @@ -29,123 +29,123 @@ */ public class RuleUtil { - public static boolean isInList(Map m, String s) { + public static boolean isInList(Map m, String s) { - Iterator it = m.keySet().iterator(); + Iterator it = m.keySet().iterator(); - while( it.hasNext() ) { - String key = (String)it.next(); - if ( key.equals(s) ) { - return true; - } - } + while( it.hasNext() ) { + String key = (String)it.next(); + if ( key.equals(s) ) { + return true; + } + } - return false; - } + return false; + } - public static boolean isInList(Collection c, String s) { + public static boolean isInList(Collection c, String s) { - Iterator it = c.iterator(); + Iterator it = c.iterator(); - while(it.hasNext()) { + while(it.hasNext()) { - Object o = it.next(); + Object o = it.next(); - if ( o instanceof String ) { + if ( o instanceof String ) { - if ( s.equals((String)o)) { - return true; - } + if ( s.equals((String)o)) { + return true; + } - } else if ( o instanceof Integer ) { + } else if ( o instanceof Integer ) { - try { - if ( Integer.parseInt(s) == ((Integer)o).intValue() ) { - return true; - } - } catch (Exception e) {} + try { + if ( Integer.parseInt(s) == ((Integer)o).intValue() ) { + return true; + } + } catch (Exception e) {} - } else if ( o instanceof Long ) { + } else if ( o instanceof Long ) { - try { - if ( Long.parseLong(s) == ((Long)o).longValue() ) { - return true; - } - } catch (Exception e) {} + try { + if ( Long.parseLong(s) == ((Long)o).longValue() ) { + return true; + } + } catch (Exception e) {} - } else if ( o instanceof Double ) { + } else if ( o instanceof Double ) { - try { - if ( Double.compare(Double.parseDouble(s), ((Double)o).doubleValue()) == 0 ) { - return true; - } - } catch (Exception e) {} - } + try { + if ( Double.compare(Double.parseDouble(s), ((Double)o).doubleValue()) == 0 ) { + return true; + } + } catch (Exception e) {} + } - } + } - return false; - } + return false; + } - /* - * Enumeration - */ - public static boolean isInList(Enumeration en, String s) { + /* + * Enumeration + */ + public static boolean isInList(Enumeration en, String s) { - for(; en.hasMoreElements();) { + for(; en.hasMoreElements();) { - Object o = en.nextElement(); + Object o = en.nextElement(); - if ( o instanceof String ) { + if ( o instanceof String ) { - if ( s.equals((String)o)) { - return true; - } + if ( s.equals((String)o)) { + return true; + } - } else if ( o instanceof Integer ) { + } else if ( o instanceof Integer ) { - try { - if ( Integer.parseInt(s) == ((Integer)o).intValue() ) { - return true; - } - } catch (Exception e) {} + try { + if ( Integer.parseInt(s) == ((Integer)o).intValue() ) { + return true; + } + } catch (Exception e) {} - } else if ( o instanceof Long ) { + } else if ( o instanceof Long ) { - try { - if ( Long.parseLong(s) == ((Long)o).longValue() ) { - return true; - } - } catch (Exception e) {} + try { + if ( Long.parseLong(s) == ((Long)o).longValue() ) { + return true; + } + } catch (Exception e) {} - } else if ( o instanceof Double ) { + } else if ( o instanceof Double ) { - try { - if ( Double.compare(Double.parseDouble(s), ((Double)o).doubleValue()) == 0 ) { - return true; - } - } catch (Exception e) {} - } + try { + if ( Double.compare(Double.parseDouble(s), ((Double)o).doubleValue()) == 0 ) { + return true; + } + } catch (Exception e) {} + } - } + } - return false; - } + return false; + } - public static boolean testValue(String s, String test, int operator) { + public static boolean testValue(String s, String test, int operator) { - switch(operator) { - case AppGuardianConfiguration.OPERATOR_EQ: + switch(operator) { + case AppGuardianConfiguration.OPERATOR_EQ: - return test.equals(s); + return test.equals(s); - case AppGuardianConfiguration.OPERATOR_CONTAINS: + case AppGuardianConfiguration.OPERATOR_CONTAINS: - return test.contains(s); + return test.contains(s); - } + } - return false; - } + return false; + } } diff --git a/src/main/java/org/owasp/esapi/waf/rules/SimpleVirtualPatchRule.java b/src/main/java/org/owasp/esapi/waf/rules/SimpleVirtualPatchRule.java index b4834fe28..bd973f54c 100644 --- a/src/main/java/org/owasp/esapi/waf/rules/SimpleVirtualPatchRule.java +++ b/src/main/java/org/owasp/esapi/waf/rules/SimpleVirtualPatchRule.java @@ -34,106 +34,106 @@ */ public class SimpleVirtualPatchRule extends Rule { - private static final String REQUEST_PARAMETERS = "request.parameters."; - private static final String REQUEST_HEADERS = "request.headers."; - - private Pattern path; - private String variable; - private Pattern valid; - private String message; - - public SimpleVirtualPatchRule(String id, Pattern path, String variable, Pattern valid, String message) { - setId(id); - this.path = path; - this.variable = variable; - this.valid = valid; - this.message = message; - } - - public Action check(HttpServletRequest req, - InterceptingHTTPServletResponse response, - HttpServletResponse httpResponse) { - - InterceptingHTTPServletRequest request = (InterceptingHTTPServletRequest)req; - - String uri = request.getRequestURI(); - if ( ! path.matcher(uri).matches() ) { - - return new DoNothingAction(); - - } else { - - /* - * Decide which parameters/headers to act on. - */ - String target = null; - Enumeration en = null; - boolean parameter = true; - - if ( variable.startsWith(REQUEST_PARAMETERS)) { - - target = variable.substring(REQUEST_PARAMETERS.length()); - en = request.getParameterNames(); - - } else if ( variable.startsWith(REQUEST_HEADERS) ) { - - parameter = false; - target = variable.substring(REQUEST_HEADERS.length()); - en = request.getHeaderNames(); - - } else { - log(request, "Patch failed (improperly configured variable '" + variable + "')"); - return new DefaultAction(); - } - - /* - * If it contains a regex character, it's a regex. Loop through elements and grab any matches. - */ - if ( target.contains("*") || target.contains("?") ) { - - target = target.replaceAll("\\*", ".*"); - Pattern p = Pattern.compile(target); - while (en.hasMoreElements() ) { - String s = (String)en.nextElement(); - String value = null; - if ( p.matcher(s).matches() ) { - if ( parameter ) { - value = request.getDictionaryParameter(s); - } else { - value = request.getHeader(s); - } - if ( value != null && ! valid.matcher(value).matches() ) { - log(request, "Virtual patch tripped on variable '" + variable + "' (specifically '" + s + "'). User input was '" + value + "' and legal pattern was '" + valid.pattern() + "': " + message); - return new DefaultAction(); - } - } - } - - return new DoNothingAction(); - - } else { - - if ( parameter ) { - String value = request.getDictionaryParameter(target); - if ( value == null || valid.matcher(value).matches() ) { - return new DoNothingAction(); - } else { - log(request, "Virtual patch tripped on parameter '" + target + "'. User input was '" + value + "' and legal pattern was '" + valid.pattern() + "': " + message); - return new DefaultAction(); - } - } else { - String value = request.getHeader(target); - if ( value == null || valid.matcher(value).matches() ) { - return new DoNothingAction(); - } else { - log(request, "Virtual patch tripped on header '" + target + "'. User input was '" + value + "' and legal pattern was '" + valid.pattern() + "': " + message); - return new DefaultAction(); - } - } - } - - } - - } + private static final String REQUEST_PARAMETERS = "request.parameters."; + private static final String REQUEST_HEADERS = "request.headers."; + + private Pattern path; + private String variable; + private Pattern valid; + private String message; + + public SimpleVirtualPatchRule(String id, Pattern path, String variable, Pattern valid, String message) { + setId(id); + this.path = path; + this.variable = variable; + this.valid = valid; + this.message = message; + } + + public Action check(HttpServletRequest req, + InterceptingHTTPServletResponse response, + HttpServletResponse httpResponse) { + + InterceptingHTTPServletRequest request = (InterceptingHTTPServletRequest)req; + + String uri = request.getRequestURI(); + if ( ! path.matcher(uri).matches() ) { + + return new DoNothingAction(); + + } else { + + /* + * Decide which parameters/headers to act on. + */ + String target = null; + Enumeration en = null; + boolean parameter = true; + + if ( variable.startsWith(REQUEST_PARAMETERS)) { + + target = variable.substring(REQUEST_PARAMETERS.length()); + en = request.getParameterNames(); + + } else if ( variable.startsWith(REQUEST_HEADERS) ) { + + parameter = false; + target = variable.substring(REQUEST_HEADERS.length()); + en = request.getHeaderNames(); + + } else { + log(request, "Patch failed (improperly configured variable '" + variable + "')"); + return new DefaultAction(); + } + + /* + * If it contains a regex character, it's a regex. Loop through elements and grab any matches. + */ + if ( target.contains("*") || target.contains("?") ) { + + target = target.replaceAll("\\*", ".*"); + Pattern p = Pattern.compile(target); + while (en.hasMoreElements() ) { + String s = (String)en.nextElement(); + String value = null; + if ( p.matcher(s).matches() ) { + if ( parameter ) { + value = request.getDictionaryParameter(s); + } else { + value = request.getHeader(s); + } + if ( value != null && ! valid.matcher(value).matches() ) { + log(request, "Virtual patch tripped on variable '" + variable + "' (specifically '" + s + "'). User input was '" + value + "' and legal pattern was '" + valid.pattern() + "': " + message); + return new DefaultAction(); + } + } + } + + return new DoNothingAction(); + + } else { + + if ( parameter ) { + String value = request.getDictionaryParameter(target); + if ( value == null || valid.matcher(value).matches() ) { + return new DoNothingAction(); + } else { + log(request, "Virtual patch tripped on parameter '" + target + "'. User input was '" + value + "' and legal pattern was '" + valid.pattern() + "': " + message); + return new DefaultAction(); + } + } else { + String value = request.getHeader(target); + if ( value == null || valid.matcher(value).matches() ) { + return new DoNothingAction(); + } else { + log(request, "Virtual patch tripped on header '" + target + "'. User input was '" + value + "' and legal pattern was '" + valid.pattern() + "': " + message); + return new DefaultAction(); + } + } + } + + } + + } } diff --git a/src/test/java/org/owasp/esapi/SecurityConfigurationWrapper.java b/src/test/java/org/owasp/esapi/SecurityConfigurationWrapper.java index a051d6f39..5cc0daf29 100644 --- a/src/test/java/org/owasp/esapi/SecurityConfigurationWrapper.java +++ b/src/test/java/org/owasp/esapi/SecurityConfigurationWrapper.java @@ -19,560 +19,560 @@ */ public class SecurityConfigurationWrapper implements SecurityConfiguration { - private SecurityConfiguration wrapped; - - /** - * Constructor wrapping the given configuration. - * @param wrapped The configuration to wrap. - */ - public SecurityConfigurationWrapper(SecurityConfiguration wrapped) - { - this.wrapped = wrapped; - } - - /** - * Access the wrapped configuration. - * @return The wrapped configuration. - */ - public SecurityConfiguration getWrappedSecurityConfiguration() - { - return wrapped; - } - - /** - * {@inheritDoc} - */ - // @Override - public String getApplicationName() - { - return wrapped.getApplicationName(); - } - - /** - * {@inheritDoc} - */ - // @Override - public String getLogImplementation() - { - return wrapped.getLogImplementation(); - } - - /** - * {@inheritDoc} - */ - // @Override - public String getAuthenticationImplementation() - { - return wrapped.getAuthenticationImplementation(); - } - - /** - * {@inheritDoc} - */ - // @Override - public String getEncoderImplementation() - { - return wrapped.getEncoderImplementation(); - } - - /** - * {@inheritDoc} - */ - // @Override - public String getAccessControlImplementation() - { - return wrapped.getAccessControlImplementation(); - } - - /** - * {@inheritDoc} - */ - // @Override - public String getIntrusionDetectionImplementation() - { - return wrapped.getIntrusionDetectionImplementation(); - } - - /** - * {@inheritDoc} - */ - // @Override - public String getRandomizerImplementation() - { - return wrapped.getRandomizerImplementation(); - } - - /** - * {@inheritDoc} - */ - // @Override - public String getEncryptionImplementation() - { - return wrapped.getEncryptionImplementation(); - } - - /** - * {@inheritDoc} - */ - // @Override - public String getValidationImplementation() - { - return wrapped.getValidationImplementation(); - } - - /** - * {@inheritDoc} - */ - // @Override - public Pattern getValidationPattern( String typeName ) - { - return wrapped.getValidationPattern(typeName); - } - - /** - * {@inheritDoc} - */ - // @Override - public String getExecutorImplementation() - { - return wrapped.getExecutorImplementation(); - } - - /** - * {@inheritDoc} - */ - // @Override - public String getHTTPUtilitiesImplementation() - { - return wrapped.getHTTPUtilitiesImplementation(); - } - - /** - * {@inheritDoc} - */ - // @Override - public byte[] getMasterKey() - { - return wrapped.getMasterKey(); - } - - /** - * {@inheritDoc} - */ - // @Override - public File getUploadDirectory() - { - return wrapped.getUploadDirectory(); - } - - /** - * {@inheritDoc} - */ - // @Override - public File getUploadTempDirectory() - { - return wrapped.getUploadTempDirectory(); - } - - /** - * {@inheritDoc} - */ - // @Override - public int getEncryptionKeyLength() - { - return wrapped.getEncryptionKeyLength(); - } + private SecurityConfiguration wrapped; + + /** + * Constructor wrapping the given configuration. + * @param wrapped The configuration to wrap. + */ + public SecurityConfigurationWrapper(SecurityConfiguration wrapped) + { + this.wrapped = wrapped; + } + + /** + * Access the wrapped configuration. + * @return The wrapped configuration. + */ + public SecurityConfiguration getWrappedSecurityConfiguration() + { + return wrapped; + } + + /** + * {@inheritDoc} + */ + // @Override + public String getApplicationName() + { + return wrapped.getApplicationName(); + } + + /** + * {@inheritDoc} + */ + // @Override + public String getLogImplementation() + { + return wrapped.getLogImplementation(); + } + + /** + * {@inheritDoc} + */ + // @Override + public String getAuthenticationImplementation() + { + return wrapped.getAuthenticationImplementation(); + } + + /** + * {@inheritDoc} + */ + // @Override + public String getEncoderImplementation() + { + return wrapped.getEncoderImplementation(); + } + + /** + * {@inheritDoc} + */ + // @Override + public String getAccessControlImplementation() + { + return wrapped.getAccessControlImplementation(); + } + + /** + * {@inheritDoc} + */ + // @Override + public String getIntrusionDetectionImplementation() + { + return wrapped.getIntrusionDetectionImplementation(); + } + + /** + * {@inheritDoc} + */ + // @Override + public String getRandomizerImplementation() + { + return wrapped.getRandomizerImplementation(); + } + + /** + * {@inheritDoc} + */ + // @Override + public String getEncryptionImplementation() + { + return wrapped.getEncryptionImplementation(); + } + + /** + * {@inheritDoc} + */ + // @Override + public String getValidationImplementation() + { + return wrapped.getValidationImplementation(); + } + + /** + * {@inheritDoc} + */ + // @Override + public Pattern getValidationPattern( String typeName ) + { + return wrapped.getValidationPattern(typeName); + } - /** - * {@inheritDoc} - */ - // @Override - public byte[] getMasterSalt() - { - return wrapped.getMasterSalt(); - } - - /** - * {@inheritDoc} - */ - // @Override - public List getAllowedExecutables() - { - return wrapped.getAllowedExecutables(); - } - - /** - * {@inheritDoc} - */ - // @Override - public List getAllowedFileExtensions() - { - return wrapped.getAllowedFileExtensions(); - } - - /** - * {@inheritDoc} - */ - // @Override - public int getAllowedFileUploadSize() - { - return wrapped.getAllowedFileUploadSize(); - } - - /** - * {@inheritDoc} - */ - // @Override - public String getPasswordParameterName() - { - return wrapped.getPasswordParameterName(); - } - - /** - * {@inheritDoc} - */ - // @Override - public String getUsernameParameterName() - { - return wrapped.getUsernameParameterName(); - } - - /** - * {@inheritDoc} - */ - // @Override - public String getEncryptionAlgorithm() - { - return wrapped.getEncryptionAlgorithm(); - } - - /** - * {@inheritDoc} - */ - // @Override - public String getCipherTransformation() - { - return wrapped.getCipherTransformation(); - } - - /** - * {@inheritDoc} - */ - // @Override - public String setCipherTransformation(String cipherXform) - { - return wrapped.setCipherTransformation(cipherXform); - } - - /** - * {@inheritDoc} - */ - // @Override - public boolean useMACforCipherText() - { - return wrapped.useMACforCipherText(); - } - - /** - * {@inheritDoc} - */ - // @Override - public boolean overwritePlainText() - { - return wrapped.overwritePlainText(); - } - - /** - * {@inheritDoc} - */ - // @Override - public String getIVType() - { - return wrapped.getIVType(); - } - - - /** - * {@inheritDoc} - */ - // @Override - public String getHashAlgorithm() - { - return wrapped.getHashAlgorithm(); - } - - /** - * {@inheritDoc} - */ - // @Override - public int getHashIterations() - { - return wrapped.getHashIterations(); - } - - /** - * {@inheritDoc} - */ - // @Override - public String getCharacterEncoding() - { - return wrapped.getCharacterEncoding(); - } - - /** - * {@inheritDoc} - */ - // @Override - public boolean getAllowMultipleEncoding() - { - return wrapped.getAllowMultipleEncoding(); - } - - /** - * {@inheritDoc} - */ - // @Override - public boolean getAllowMixedEncoding() - { - return wrapped.getAllowMixedEncoding(); - } - - /** - * {@inheritDoc} - */ - // @Override - public List getDefaultCanonicalizationCodecs() - { - return wrapped.getDefaultCanonicalizationCodecs(); - } - - /** - * {@inheritDoc} - */ - // @Override - public String getDigitalSignatureAlgorithm() - { - return wrapped.getDigitalSignatureAlgorithm(); - } - - /** - * {@inheritDoc} - */ - // @Override - public int getDigitalSignatureKeyLength() - { - return wrapped.getDigitalSignatureKeyLength(); - } - - /** - * {@inheritDoc} - */ - // @Override - public String getRandomAlgorithm() - { - return wrapped.getRandomAlgorithm(); - } - - /** - * {@inheritDoc} - */ - // @Override - public int getAllowedLoginAttempts() - { - return wrapped.getAllowedLoginAttempts(); - } - - /** - * {@inheritDoc} - */ - // @Override - public int getMaxOldPasswordHashes() - { - return wrapped.getMaxOldPasswordHashes(); - } - - /** - * {@inheritDoc} - */ - // @Override - public Threshold getQuota(String eventName) - { - return wrapped.getQuota(eventName); - } - - /** - * {@inheritDoc} - */ - // @Override - public File getResourceFile( String filename ) - { - return wrapped.getResourceFile(filename); - } + /** + * {@inheritDoc} + */ + // @Override + public String getExecutorImplementation() + { + return wrapped.getExecutorImplementation(); + } + + /** + * {@inheritDoc} + */ + // @Override + public String getHTTPUtilitiesImplementation() + { + return wrapped.getHTTPUtilitiesImplementation(); + } + + /** + * {@inheritDoc} + */ + // @Override + public byte[] getMasterKey() + { + return wrapped.getMasterKey(); + } + + /** + * {@inheritDoc} + */ + // @Override + public File getUploadDirectory() + { + return wrapped.getUploadDirectory(); + } + + /** + * {@inheritDoc} + */ + // @Override + public File getUploadTempDirectory() + { + return wrapped.getUploadTempDirectory(); + } + + /** + * {@inheritDoc} + */ + // @Override + public int getEncryptionKeyLength() + { + return wrapped.getEncryptionKeyLength(); + } + + /** + * {@inheritDoc} + */ + // @Override + public byte[] getMasterSalt() + { + return wrapped.getMasterSalt(); + } + + /** + * {@inheritDoc} + */ + // @Override + public List getAllowedExecutables() + { + return wrapped.getAllowedExecutables(); + } + + /** + * {@inheritDoc} + */ + // @Override + public List getAllowedFileExtensions() + { + return wrapped.getAllowedFileExtensions(); + } + + /** + * {@inheritDoc} + */ + // @Override + public int getAllowedFileUploadSize() + { + return wrapped.getAllowedFileUploadSize(); + } + + /** + * {@inheritDoc} + */ + // @Override + public String getPasswordParameterName() + { + return wrapped.getPasswordParameterName(); + } + + /** + * {@inheritDoc} + */ + // @Override + public String getUsernameParameterName() + { + return wrapped.getUsernameParameterName(); + } + + /** + * {@inheritDoc} + */ + // @Override + public String getEncryptionAlgorithm() + { + return wrapped.getEncryptionAlgorithm(); + } + + /** + * {@inheritDoc} + */ + // @Override + public String getCipherTransformation() + { + return wrapped.getCipherTransformation(); + } + + /** + * {@inheritDoc} + */ + // @Override + public String setCipherTransformation(String cipherXform) + { + return wrapped.setCipherTransformation(cipherXform); + } + + /** + * {@inheritDoc} + */ + // @Override + public boolean useMACforCipherText() + { + return wrapped.useMACforCipherText(); + } + + /** + * {@inheritDoc} + */ + // @Override + public boolean overwritePlainText() + { + return wrapped.overwritePlainText(); + } + + /** + * {@inheritDoc} + */ + // @Override + public String getIVType() + { + return wrapped.getIVType(); + } + + + /** + * {@inheritDoc} + */ + // @Override + public String getHashAlgorithm() + { + return wrapped.getHashAlgorithm(); + } + + /** + * {@inheritDoc} + */ + // @Override + public int getHashIterations() + { + return wrapped.getHashIterations(); + } + + /** + * {@inheritDoc} + */ + // @Override + public String getCharacterEncoding() + { + return wrapped.getCharacterEncoding(); + } + + /** + * {@inheritDoc} + */ + // @Override + public boolean getAllowMultipleEncoding() + { + return wrapped.getAllowMultipleEncoding(); + } + + /** + * {@inheritDoc} + */ + // @Override + public boolean getAllowMixedEncoding() + { + return wrapped.getAllowMixedEncoding(); + } + + /** + * {@inheritDoc} + */ + // @Override + public List getDefaultCanonicalizationCodecs() + { + return wrapped.getDefaultCanonicalizationCodecs(); + } + + /** + * {@inheritDoc} + */ + // @Override + public String getDigitalSignatureAlgorithm() + { + return wrapped.getDigitalSignatureAlgorithm(); + } + + /** + * {@inheritDoc} + */ + // @Override + public int getDigitalSignatureKeyLength() + { + return wrapped.getDigitalSignatureKeyLength(); + } + + /** + * {@inheritDoc} + */ + // @Override + public String getRandomAlgorithm() + { + return wrapped.getRandomAlgorithm(); + } + + /** + * {@inheritDoc} + */ + // @Override + public int getAllowedLoginAttempts() + { + return wrapped.getAllowedLoginAttempts(); + } + + /** + * {@inheritDoc} + */ + // @Override + public int getMaxOldPasswordHashes() + { + return wrapped.getMaxOldPasswordHashes(); + } + + /** + * {@inheritDoc} + */ + // @Override + public Threshold getQuota(String eventName) + { + return wrapped.getQuota(eventName); + } + + /** + * {@inheritDoc} + */ + // @Override + public File getResourceFile( String filename ) + { + return wrapped.getResourceFile(filename); + } - /** - * {@inheritDoc} - */ - // @Override - public boolean getForceHttpOnlySession() - { - return wrapped.getForceHttpOnlySession(); - } - - /** - * {@inheritDoc} - */ - // @Override - public boolean getForceSecureSession() - { - return wrapped.getForceSecureSession(); - } - - /** - * {@inheritDoc} - */ - // @Override - public boolean getForceHttpOnlyCookies() - { - return wrapped.getForceHttpOnlyCookies(); - } - - /** - * {@inheritDoc} - */ - // @Override - public boolean getForceSecureCookies() - { - return wrapped.getForceSecureCookies(); - } - - /** - * {@inheritDoc} - */ - // @Override - public int getMaxHttpHeaderSize() { + /** + * {@inheritDoc} + */ + // @Override + public boolean getForceHttpOnlySession() + { + return wrapped.getForceHttpOnlySession(); + } + + /** + * {@inheritDoc} + */ + // @Override + public boolean getForceSecureSession() + { + return wrapped.getForceSecureSession(); + } + + /** + * {@inheritDoc} + */ + // @Override + public boolean getForceHttpOnlyCookies() + { + return wrapped.getForceHttpOnlyCookies(); + } + + /** + * {@inheritDoc} + */ + // @Override + public boolean getForceSecureCookies() + { + return wrapped.getForceSecureCookies(); + } + + /** + * {@inheritDoc} + */ + // @Override + public int getMaxHttpHeaderSize() { return wrapped.getMaxHttpHeaderSize(); - } - - /** - * {@inheritDoc} - */ - // @Override - public InputStream getResourceStream( String filename ) throws IOException - { - return wrapped.getResourceStream(filename); - } - - - /** - * {@inheritDoc} - */ - // @Override - public void setResourceDirectory(String dir) - { - wrapped.setResourceDirectory(dir); - } - - /** - * {@inheritDoc} - */ - // @Override - public String getResponseContentType() - { - return wrapped.getResponseContentType(); - } - - /** - * {@inheritDoc} - */ - // @Override - public String getHttpSessionIdName() { - return wrapped.getHttpSessionIdName(); - } - - /** - * {@inheritDoc} - */ - // @Override - public long getRememberTokenDuration() - { - return wrapped.getRememberTokenDuration(); - } - - /** - * {@inheritDoc} - */ - // @Override - public int getSessionIdleTimeoutLength() - { - return wrapped.getSessionIdleTimeoutLength(); - } - - /** - * {@inheritDoc} - */ - // @Override - public int getSessionAbsoluteTimeoutLength() - { - return wrapped.getSessionAbsoluteTimeoutLength(); - } - - /** - * {@inheritDoc} - */ - // @Override - public boolean getLogEncodingRequired() - { - return wrapped.getLogEncodingRequired(); - } - - /** - * {@inheritDoc} - */ - // @Override - public boolean getLogApplicationName() - { - return wrapped.getLogApplicationName(); - } - - /** - * {@inheritDoc} - */ - // @Override - public boolean getLogServerIP() - { - return wrapped.getLogServerIP(); - } - - @Override - public int getIntProp(String propertyName) throws ConfigurationException { - return wrapped.getIntProp(propertyName); - } - - @Override - public byte[] getByteArrayProp(String propertyName) throws ConfigurationException { - return wrapped.getByteArrayProp(propertyName); - } - - @Override - public Boolean getBooleanProp(String propertyName) throws ConfigurationException { - return wrapped.getBooleanProp(propertyName); - } - - @Override - public String getStringProp(String propertyName) throws ConfigurationException { - return wrapped.getStringProp(propertyName); - } - - /** - * {@inheritDoc} - */ - // @Override - public File getWorkingDirectory() - { - return wrapped.getWorkingDirectory(); - } - - /** + } + + /** + * {@inheritDoc} + */ + // @Override + public InputStream getResourceStream( String filename ) throws IOException + { + return wrapped.getResourceStream(filename); + } + + + /** + * {@inheritDoc} + */ + // @Override + public void setResourceDirectory(String dir) + { + wrapped.setResourceDirectory(dir); + } + + /** + * {@inheritDoc} + */ + // @Override + public String getResponseContentType() + { + return wrapped.getResponseContentType(); + } + + /** + * {@inheritDoc} + */ + // @Override + public String getHttpSessionIdName() { + return wrapped.getHttpSessionIdName(); + } + + /** + * {@inheritDoc} + */ + // @Override + public long getRememberTokenDuration() + { + return wrapped.getRememberTokenDuration(); + } + + /** + * {@inheritDoc} + */ + // @Override + public int getSessionIdleTimeoutLength() + { + return wrapped.getSessionIdleTimeoutLength(); + } + + /** + * {@inheritDoc} + */ + // @Override + public int getSessionAbsoluteTimeoutLength() + { + return wrapped.getSessionAbsoluteTimeoutLength(); + } + + /** + * {@inheritDoc} + */ + // @Override + public boolean getLogEncodingRequired() + { + return wrapped.getLogEncodingRequired(); + } + + /** + * {@inheritDoc} + */ + // @Override + public boolean getLogApplicationName() + { + return wrapped.getLogApplicationName(); + } + + /** + * {@inheritDoc} + */ + // @Override + public boolean getLogServerIP() + { + return wrapped.getLogServerIP(); + } + + @Override + public int getIntProp(String propertyName) throws ConfigurationException { + return wrapped.getIntProp(propertyName); + } + + @Override + public byte[] getByteArrayProp(String propertyName) throws ConfigurationException { + return wrapped.getByteArrayProp(propertyName); + } + + @Override + public Boolean getBooleanProp(String propertyName) throws ConfigurationException { + return wrapped.getBooleanProp(propertyName); + } + + @Override + public String getStringProp(String propertyName) throws ConfigurationException { + return wrapped.getStringProp(propertyName); + } + + /** + * {@inheritDoc} + */ + // @Override + public File getWorkingDirectory() + { + return wrapped.getWorkingDirectory(); + } + + /** * {@inheritDoc} */ // @Override @@ -595,26 +595,26 @@ public String getPreferredJCEProvider() { return wrapped.getPreferredJCEProvider(); } - /** - * {@inheritDoc} - */ - // @Override - public boolean getDisableIntrusionDetection() { - return wrapped.getDisableIntrusionDetection(); - } - - /** - * {@inheritDoc} - */ - // @Override - public String getKDFPseudoRandomFunction() { - return wrapped.getKDFPseudoRandomFunction(); - } - - /** - * {@inheritDoc} - */ - public boolean getLenientDatesAccepted() { - return wrapped.getLenientDatesAccepted(); - } + /** + * {@inheritDoc} + */ + // @Override + public boolean getDisableIntrusionDetection() { + return wrapped.getDisableIntrusionDetection(); + } + + /** + * {@inheritDoc} + */ + // @Override + public String getKDFPseudoRandomFunction() { + return wrapped.getKDFPseudoRandomFunction(); + } + + /** + * {@inheritDoc} + */ + public boolean getLenientDatesAccepted() { + return wrapped.getLenientDatesAccepted(); + } } diff --git a/src/test/java/org/owasp/esapi/StringUtilitiesTest.java b/src/test/java/org/owasp/esapi/StringUtilitiesTest.java index 967b63263..6865459ce 100644 --- a/src/test/java/org/owasp/esapi/StringUtilitiesTest.java +++ b/src/test/java/org/owasp/esapi/StringUtilitiesTest.java @@ -9,12 +9,12 @@ public class StringUtilitiesTest extends TestCase { - /** + /** * Run all the test cases in this suite. * This is to allow running from {@code org.owasp.esapi.AllTests}. * - * @return the test - */ + * @return the test + */ public static Test suite() { TestSuite suite = new TestSuite(StringUtilitiesTest.class); return suite; @@ -22,61 +22,61 @@ public static Test suite() { /** Test the getLevenshteinDistance() method. */ public void testGetLevenshteinDistance() { - String src = "GUMBO"; - String target = "GAMBOL"; - assertTrue( 2 == StringUtilities.getLevenshteinDistance(src, target) ); - assertTrue( 2 == StringUtilities.getLevenshteinDistance(target, src) ); - assertTrue( 0 == StringUtilities.getLevenshteinDistance(src, src) ); - assertTrue( 5 == StringUtilities.getLevenshteinDistance(src, "") ); - assertTrue( 6 == StringUtilities.getLevenshteinDistance("", target) ); + String src = "GUMBO"; + String target = "GAMBOL"; + assertTrue( 2 == StringUtilities.getLevenshteinDistance(src, target) ); + assertTrue( 2 == StringUtilities.getLevenshteinDistance(target, src) ); + assertTrue( 0 == StringUtilities.getLevenshteinDistance(src, src) ); + assertTrue( 5 == StringUtilities.getLevenshteinDistance(src, "") ); + assertTrue( 6 == StringUtilities.getLevenshteinDistance("", target) ); - try { - @SuppressWarnings("unused") - int ldist = StringUtilities.getLevenshteinDistance(null, "abc"); - } catch ( IllegalArgumentException ex ) { - assertTrue( ex.getClass().getName().equals( IllegalArgumentException.class.getName() )); - } + try { + @SuppressWarnings("unused") + int ldist = StringUtilities.getLevenshteinDistance(null, "abc"); + } catch ( IllegalArgumentException ex ) { + assertTrue( ex.getClass().getName().equals( IllegalArgumentException.class.getName() )); + } - try { - @SuppressWarnings("unused") - int ldist = StringUtilities.getLevenshteinDistance("abc", null); - } catch ( IllegalArgumentException ex ) { - assertTrue( ex.getClass().getName().equals( IllegalArgumentException.class.getName() )); - } + try { + @SuppressWarnings("unused") + int ldist = StringUtilities.getLevenshteinDistance("abc", null); + } catch ( IllegalArgumentException ex ) { + assertTrue( ex.getClass().getName().equals( IllegalArgumentException.class.getName() )); + } } /** Test the union() method. */ public void testUnion() { - char[] a1 = { 'a', 'b', 'c' }; - char[] a2 = { 'c', 'd', 'e' }; - char[] union = StringUtilities.union(a1, a2); - assertTrue( Arrays.equals( union, new char[] {'a','b','c','d','e' } ) ); + char[] a1 = { 'a', 'b', 'c' }; + char[] a2 = { 'c', 'd', 'e' }; + char[] union = StringUtilities.union(a1, a2); + assertTrue( Arrays.equals( union, new char[] {'a','b','c','d','e' } ) ); } /** Test the contains() method. */ public void contains() { - StringBuilder sb = new StringBuilder( "abc" ); - assertTrue( StringUtilities.contains(sb, 'b') ); - assertFalse( StringUtilities.contains(sb, 'x') ); + StringBuilder sb = new StringBuilder( "abc" ); + assertTrue( StringUtilities.contains(sb, 'b') ); + assertFalse( StringUtilities.contains(sb, 'x') ); } /** Test the notNullOrEmpty() method. */ public void testNotNullOrEmpty() { - String str = "A string"; - assertTrue( StringUtilities.notNullOrEmpty(str, false) ); - assertTrue( StringUtilities.notNullOrEmpty(str, true) ); - str = " A string "; - assertTrue( StringUtilities.notNullOrEmpty(str, false) ); - assertTrue( StringUtilities.notNullOrEmpty(str, true) ); - str = " "; - assertTrue( StringUtilities.notNullOrEmpty(str, false) ); - assertFalse( StringUtilities.notNullOrEmpty(str, true) ); - str = ""; - assertFalse( StringUtilities.notNullOrEmpty(str, false) ); - assertFalse( StringUtilities.notNullOrEmpty(str, true) ); - str = null; - assertFalse( StringUtilities.notNullOrEmpty(str, false) ); - assertFalse( StringUtilities.notNullOrEmpty(str, true) ); + String str = "A string"; + assertTrue( StringUtilities.notNullOrEmpty(str, false) ); + assertTrue( StringUtilities.notNullOrEmpty(str, true) ); + str = " A string "; + assertTrue( StringUtilities.notNullOrEmpty(str, false) ); + assertTrue( StringUtilities.notNullOrEmpty(str, true) ); + str = " "; + assertTrue( StringUtilities.notNullOrEmpty(str, false) ); + assertFalse( StringUtilities.notNullOrEmpty(str, true) ); + str = ""; + assertFalse( StringUtilities.notNullOrEmpty(str, false) ); + assertFalse( StringUtilities.notNullOrEmpty(str, true) ); + str = null; + assertFalse( StringUtilities.notNullOrEmpty(str, false) ); + assertFalse( StringUtilities.notNullOrEmpty(str, true) ); } public void testReplaceNull() { diff --git a/src/test/java/org/owasp/esapi/UserTest.java b/src/test/java/org/owasp/esapi/UserTest.java index 62b465bec..3292643b7 100644 --- a/src/test/java/org/owasp/esapi/UserTest.java +++ b/src/test/java/org/owasp/esapi/UserTest.java @@ -24,83 +24,83 @@ */ public class UserTest extends TestCase { - public UserTest(String testName) { - super(testName); - } + public UserTest(String testName) { + super(testName); + } - protected void setUp() throws Exception { - // none - } + protected void setUp() throws Exception { + // none + } - protected void tearDown() throws Exception { - // none - } + protected void tearDown() throws Exception { + // none + } - public static Test suite() { - TestSuite suite = new TestSuite(UserTest.class); - return suite; - } - - public void testAllMethods() throws Exception { - // create a user to test Anonymous - String accountName = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS); - Authenticator instance = ESAPI.authenticator(); - String password = instance.generateStrongPassword(); - - // Probably could skip the assignment here, but maybe someone had - // future plans to use this. So will just suppress warning for now. - @SuppressWarnings("unused") - User user = instance.createUser(accountName, password, password); - - // test the rest of the Anonymous user - try { User.ANONYMOUS.addRole(null); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.addRoles(null); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.changePassword(null, null, null); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.disable(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.enable(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.getAccountId(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.getAccountName(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.getName(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.getCSRFToken(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.getExpirationTime(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.getFailedLoginCount(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.getLastFailedLoginTime(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.getLastLoginTime(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.getLastPasswordChangeTime(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.getRoles(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.getScreenName(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.addSession(null); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.removeSession(null); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.incrementFailedLoginCount(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.isAnonymous(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.isEnabled(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.isExpired(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.isInRole(null); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.isLocked(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.isLoggedIn(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.isSessionAbsoluteTimeout(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.isSessionTimeout(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.lock(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.loginWithPassword(null); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.logout(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.removeRole(null); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.resetCSRFToken(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.setAccountName(null); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.setExpirationTime(null); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.setRoles(null); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.setScreenName(null); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.unlock(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.verifyPassword(null); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.setLastFailedLoginTime(null); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.setLastLoginTime(null); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.setLastHostAddress(null); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.setLastPasswordChangeTime(null); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.getEventMap(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.getLocale(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.setLocale(null); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.getAccountName(); } catch( RuntimeException e ) {} - try { User.ANONYMOUS.getAccountName(); } catch( RuntimeException e ) {} - } + public static Test suite() { + TestSuite suite = new TestSuite(UserTest.class); + return suite; + } + + public void testAllMethods() throws Exception { + // create a user to test Anonymous + String accountName = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS); + Authenticator instance = ESAPI.authenticator(); + String password = instance.generateStrongPassword(); + + // Probably could skip the assignment here, but maybe someone had + // future plans to use this. So will just suppress warning for now. + @SuppressWarnings("unused") + User user = instance.createUser(accountName, password, password); + + // test the rest of the Anonymous user + try { User.ANONYMOUS.addRole(null); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.addRoles(null); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.changePassword(null, null, null); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.disable(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.enable(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.getAccountId(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.getAccountName(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.getName(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.getCSRFToken(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.getExpirationTime(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.getFailedLoginCount(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.getLastFailedLoginTime(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.getLastLoginTime(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.getLastPasswordChangeTime(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.getRoles(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.getScreenName(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.addSession(null); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.removeSession(null); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.incrementFailedLoginCount(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.isAnonymous(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.isEnabled(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.isExpired(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.isInRole(null); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.isLocked(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.isLoggedIn(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.isSessionAbsoluteTimeout(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.isSessionTimeout(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.lock(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.loginWithPassword(null); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.logout(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.removeRole(null); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.resetCSRFToken(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.setAccountName(null); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.setExpirationTime(null); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.setRoles(null); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.setScreenName(null); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.unlock(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.verifyPassword(null); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.setLastFailedLoginTime(null); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.setLastLoginTime(null); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.setLastHostAddress(null); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.setLastPasswordChangeTime(null); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.getEventMap(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.getLocale(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.setLocale(null); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.getAccountName(); } catch( RuntimeException e ) {} + try { User.ANONYMOUS.getAccountName(); } catch( RuntimeException e ) {} + } } diff --git a/src/test/java/org/owasp/esapi/codecs/AbstractCodecTest.java b/src/test/java/org/owasp/esapi/codecs/AbstractCodecTest.java index 813330ed6..a557796e4 100644 --- a/src/test/java/org/owasp/esapi/codecs/AbstractCodecTest.java +++ b/src/test/java/org/owasp/esapi/codecs/AbstractCodecTest.java @@ -78,552 +78,552 @@ public static Test suite() { return suite; } - public void testHtmlEncode() - { - assertEquals( "test", htmlCodec.encode( EMPTY_CHAR_ARRAY, "test") ); - } - - public void testPercentEncode() - { - assertEquals( "%3C", percentCodec.encode(EMPTY_CHAR_ARRAY, "<") ); - } - - - public void testJavaScriptEncode() - { - assertEquals( "\\x3C", javaScriptCodec.encode(EMPTY_CHAR_ARRAY, "<") ); - } - - public void testVBScriptEncode() - { - assertEquals( "chrw(60)", vbScriptCodec.encode(EMPTY_CHAR_ARRAY, "<") ); - } - - public void testCSSEncode() - { - assertEquals( "\\3c ", cssCodec.encode(EMPTY_CHAR_ARRAY, "<") ); - } - - public void testCSSInvalidCodepointDecode() - { - assertEquals("\uFFFDg", cssCodec.decode("\\abcdefg") ); - } - - public void testMySQLANSCIEncode() - { - assertEquals( "\'\'", mySQLCodecANSI.encode(EMPTY_CHAR_ARRAY, "\'") ); - } - - public void testMySQLStandardEncode() - { - assertEquals( "\\<", mySQLCodecStandard.encode(EMPTY_CHAR_ARRAY, "<") ); - } - - public void testOracleEncode() - { - assertEquals( "\'\'", oracleCodec.encode(EMPTY_CHAR_ARRAY, "\'") ); - } - - public void testUnixEncode() - { - assertEquals( "\\<", unixCodec.encode(EMPTY_CHAR_ARRAY, "<") ); - } - - public void testWindowsEncode() - { - assertEquals( "^<", windowsCodec.encode(EMPTY_CHAR_ARRAY, "<") ); - } - - - public void testHtmlEncodeChar() - { - - assertEquals( "<", htmlCodec.encodeCharacter(EMPTY_CHAR_ARRAY, (int) LESS_THAN) ); - } - - public void testHtmlEncodeChar0x100() - { - Character in = 0x100; - String inStr = Character.toString(in); - String expected = "Ā"; - String result; - //The new default for HTMLEntityCodec is ints/Integers. Use Character/char at your own risk! - //Characters destroy non-BMP codepoints. This Codec is now supposed surpass that. - result = htmlCodec.encodeCharacter(EMPTY_CHAR_ARRAY, (int) in); - // this should be escaped - assertFalse(inStr.equals(result)); - // UTF-8 encoded and then percent escaped - assertEquals(expected, result); - } - - public void testHtmlEncodeStr0x100() - { - Character in = 0x100; - String inStr = Character.toString(in); - String expected = "Ā"; - String result; - - result = htmlCodec.encode(EMPTY_CHAR_ARRAY, inStr); - // this should be escaped - assertFalse(inStr.equals(result)); - // UTF-8 encoded and then percent escaped - assertEquals(expected, result); - } - - public void testPercentEncodeChar() - { - assertEquals( "%3C", percentCodec.encodeCharacter(EMPTY_CHAR_ARRAY, LESS_THAN) ); - } - - public void testPercentEncodeChar0x100() - { - Character in = 0x100; - String inStr = Character.toString(in); - String expected = "%C4%80"; - String result; - - result = percentCodec.encodeCharacter(EMPTY_CHAR_ARRAY, in); - // this should be escaped - assertFalse(inStr.equals(result)); - // UTF-8 encoded and then percent escaped - assertEquals(expected, result); - } - - public void testPercentEncodeStr0x100() - { - Character in = 0x100; - String inStr = Character.toString(in); - String expected = "%C4%80"; - String result; - - result = percentCodec.encode(EMPTY_CHAR_ARRAY, inStr); - // this should be escaped - assertFalse(inStr.equals(result)); - // UTF-8 encoded and then percent escaped - assertEquals(expected, result); - } - - public void testJavaScriptEncodeChar() - { - assertEquals( "\\x3C", javaScriptCodec.encodeCharacter(EMPTY_CHAR_ARRAY, LESS_THAN) ); - } - - public void testJavaScriptEncodeChar0x100() - { - Character in = 0x100; - String inStr = Character.toString(in); - String expected = "\\u0100"; - String result; - - result = javaScriptCodec.encodeCharacter(EMPTY_CHAR_ARRAY, in); - // this should be escaped - assertFalse(inStr.equals(result)); - assertEquals(expected,result); - } - - public void testJavaScriptEncodeStr0x100() - { - Character in = 0x100; - String inStr = Character.toString(in); - String expected = "\\u0100"; - String result; - - result = javaScriptCodec.encode(EMPTY_CHAR_ARRAY, inStr); - // this should be escaped - assertFalse(inStr.equals(result)); - assertEquals(expected,result); - } + public void testHtmlEncode() + { + assertEquals( "test", htmlCodec.encode( EMPTY_CHAR_ARRAY, "test") ); + } + + public void testPercentEncode() + { + assertEquals( "%3C", percentCodec.encode(EMPTY_CHAR_ARRAY, "<") ); + } + + + public void testJavaScriptEncode() + { + assertEquals( "\\x3C", javaScriptCodec.encode(EMPTY_CHAR_ARRAY, "<") ); + } + + public void testVBScriptEncode() + { + assertEquals( "chrw(60)", vbScriptCodec.encode(EMPTY_CHAR_ARRAY, "<") ); + } + + public void testCSSEncode() + { + assertEquals( "\\3c ", cssCodec.encode(EMPTY_CHAR_ARRAY, "<") ); + } + + public void testCSSInvalidCodepointDecode() + { + assertEquals("\uFFFDg", cssCodec.decode("\\abcdefg") ); + } + + public void testMySQLANSCIEncode() + { + assertEquals( "\'\'", mySQLCodecANSI.encode(EMPTY_CHAR_ARRAY, "\'") ); + } + + public void testMySQLStandardEncode() + { + assertEquals( "\\<", mySQLCodecStandard.encode(EMPTY_CHAR_ARRAY, "<") ); + } + + public void testOracleEncode() + { + assertEquals( "\'\'", oracleCodec.encode(EMPTY_CHAR_ARRAY, "\'") ); + } + + public void testUnixEncode() + { + assertEquals( "\\<", unixCodec.encode(EMPTY_CHAR_ARRAY, "<") ); + } + + public void testWindowsEncode() + { + assertEquals( "^<", windowsCodec.encode(EMPTY_CHAR_ARRAY, "<") ); + } + + + public void testHtmlEncodeChar() + { - public void testVBScriptEncodeChar() - { - assertEquals( "chrw(60)", vbScriptCodec.encodeCharacter(EMPTY_CHAR_ARRAY, LESS_THAN) ); - } - - public void testVBScriptEncodeChar0x100() - { - Character in = 0x100; - String inStr = Character.toString(in); - // FIXME I don't know vb... - // String expected = "\\u0100"; - String result; - - result = vbScriptCodec.encodeCharacter(EMPTY_CHAR_ARRAY, in); - // this should be escaped - assertFalse(inStr.equals(result)); - //assertEquals(expected,result); - } - - public void testVBScriptEncodeStr0x100() - { - Character in = 0x100; - String inStr = Character.toString(in); - // FIXME I don't know vb... - // String expected = "chrw(0x100)"; - String result; - - result = vbScriptCodec.encode(EMPTY_CHAR_ARRAY, inStr); - // this should be escaped - assertFalse(inStr.equals(result)); - // assertEquals(expected,result); - } - - public void testCSSEncodeChar() - { - assertEquals( "\\3c ", cssCodec.encodeCharacter(EMPTY_CHAR_ARRAY, LESS_THAN) ); - } - - public void testCSSEncodeChar0x100() - { - Character in = 0x100; - String inStr = Character.toString(in); - String expected = "\\100 "; - String result; - - result = cssCodec.encodeCharacter(EMPTY_CHAR_ARRAY, in); - // this should be escaped - assertFalse(inStr.equals(result)); - assertEquals(expected,result); - } - - public void testCSSEncodeStr0x100() - { - Character in = 0x100; - String inStr = Character.toString(in); - String expected = "\\100 "; - String result; - - result = cssCodec.encode(EMPTY_CHAR_ARRAY, inStr); - // this should be escaped - assertFalse(inStr.equals(result)); - assertEquals(expected,result); - } - - public void testMySQLANSIEncodeChar() - { - assertEquals( "\'\'", mySQLCodecANSI.encodeCharacter(EMPTY_CHAR_ARRAY, SINGLE_QUOTE)); - } - - public void testMySQLStandardEncodeChar0x100() - { - Character in = 0x100; - String inStr = Character.toString(in); - String expected = "\\" + in; - String result; - - result = mySQLCodecStandard.encodeCharacter(EMPTY_CHAR_ARRAY, in); - // this should be escaped - assertFalse(inStr.equals(result)); - assertEquals(expected,result); - } - - public void testMySQLStandardEncodeStr0x100() - { - Character in = 0x100; - String inStr = Character.toString(in); - String expected = "\\" + in; - String result; - - result = mySQLCodecStandard.encode(EMPTY_CHAR_ARRAY, inStr); - // this should be escaped - assertFalse(inStr.equals(result)); - assertEquals(expected,result); - } - - public void testMySQLStandardEncodeChar() - { - assertEquals( "\\<", mySQLCodecStandard.encodeCharacter(EMPTY_CHAR_ARRAY, LESS_THAN) ); - } - - public void testOracleEncodeChar() - { - assertEquals( "\'\'", oracleCodec.encodeCharacter(EMPTY_CHAR_ARRAY, SINGLE_QUOTE) ); - } - - public void testUnixEncodeChar() - { - assertEquals( "\\<", unixCodec.encodeCharacter(EMPTY_CHAR_ARRAY, LESS_THAN) ); - } - - public void testUnixEncodeChar0x100() - { - Character in = 0x100; - String inStr = Character.toString(in); - String expected = "\\" + in; - String result; - - result = unixCodec.encodeCharacter(EMPTY_CHAR_ARRAY, in); - // this should be escaped - assertFalse(inStr.equals(result)); - assertEquals(expected,result); - } - - public void testUnixEncodeStr0x100() - { - Character in = 0x100; - String inStr = Character.toString(in); - String expected = "\\" + in; - String result; - - result = unixCodec.encode(EMPTY_CHAR_ARRAY, inStr); - // this should be escaped - assertFalse(inStr.equals(result)); - assertEquals(expected,result); - } - - public void testWindowsEncodeChar() - { - assertEquals( "^<", windowsCodec.encodeCharacter(EMPTY_CHAR_ARRAY, LESS_THAN) ); - } - - public void testWindowsEncodeChar0x100() - { - Character in = 0x100; - String inStr = Character.toString(in); - String expected = "^" + in; - String result; - - result = windowsCodec.encodeCharacter(EMPTY_CHAR_ARRAY, in); - // this should be escaped - assertFalse(inStr.equals(result)); - assertEquals(expected,result); - } - - public void testWindowsEncodeStr0x100() - { - Character in = 0x100; - String inStr = Character.toString(in); - String expected = "^" + in; - String result; - - result = windowsCodec.encode(EMPTY_CHAR_ARRAY, inStr); - // this should be escaped - assertFalse(inStr.equals(result)); - assertEquals(expected,result); - } - - public void testHtmlDecodeDecimalEntities() - { - assertEquals( "test!", htmlCodec.decode("test!") ); - } - - public void testHtmlDecodeHexEntitites() - { - assertEquals( "test!", htmlCodec.decode("test!") ); - } - - public void testHtmlDecodeInvalidAttribute() - { - assertEquals( "&jeff;", htmlCodec.decode("&jeff;") ); - } - - public void testHtmlDecodeAmp() - { - assertEquals("&", htmlCodec.decode("&")); - assertEquals("&X", htmlCodec.decode("&X")); - assertEquals("&", htmlCodec.decode("&")); - assertEquals("&X", htmlCodec.decode("&X")); - } - - public void testHtmlDecodeLt() - { - assertEquals("<", htmlCodec.decode("<")); - assertEquals(" codec = new HTMLEntityCodec(); - - @Test - public void testEntityDecoding(){ - assertEquals("<", codec.decode("<")); + Codec codec = new HTMLEntityCodec(); + + @Test + public void testEntityDecoding(){ + assertEquals("<", codec.decode("<")); assertEquals( "<", codec.decode("<")); assertEquals( "<", codec.decode("<")); assertEquals( "<", codec.decode("<")); - } - - @Test - public void test32BitCJK(){ - String s = "𡘾𦴩𥻂"; - String expected = "𡘾𦴩𥻂"; - String bad = "������"; - assertEquals(false, expected.equals(bad)); - assertEquals(expected, codec.encode(new char[0], s)); - } - - @Test - public void test32BitCJKMixedWithBmp(){ - String s = "𡘾𦴩<𥻂"; - String expected = "𡘾𦴩<𥻂"; - String bad = "������"; - assertEquals(false, expected.equals(bad)); - assertEquals(expected, codec.encode(new char[0], s)); - } - - @Test - public void testDecodeforChars(){ - String s = "!@$%()=+{}[]"; - String expected = "!@$%()=+{}[]"; - assertEquals(expected, codec.decode(s)); - } - - @Test - public void testMixedBmpAndNonBmp(){ - String nonBMP = new String(new int[]{0x2f804}, 0, 1); - String bmp = " CLASS = HashTrieTest.class; - - public HashTrieTest(String testName) - { - super(testName); - } - - public void testSingleInsertLookup() - { - HashTrie trie = new HashTrie(); - - trie.put("true", Boolean.TRUE); - assertEquals(Boolean.TRUE, trie.get("true")); - assertNull(trie.get("not there")); - assertNull(trie.get("tru")); - assertNull(trie.get("trueX")); - assertEquals("true".length(), trie.getMaxKeyLength()); - } - - public void testEmpty() - { - HashTrie trie = new HashTrie(); - assertNull(trie.get("true")); - assertNull(trie.get("false")); - assertNull(trie.get("")); - assertTrue(trie.getMaxKeyLength()<0); - } - - public void testTwoInsertLookup() - { - HashTrie trie = new HashTrie(); - - trie.put("true", Boolean.TRUE); - trie.put("false", Boolean.FALSE); - assertEquals(Boolean.TRUE, trie.get("true")); - assertEquals(Boolean.FALSE, trie.get("false")); - assertEquals("false".length(),trie.getMaxKeyLength()); - } - - public void testMatchingPrefix() - { - HashTrie trie = new HashTrie(); - - trie.put("pretrue", Boolean.TRUE); - trie.put("prefalse", Boolean.FALSE); - assertEquals(Boolean.TRUE, trie.get("pretrue")); - assertEquals(Boolean.FALSE, trie.get("prefalse")); - } - - public void testPrefixIsValidKey() - { - HashTrie trie = new HashTrie(); - - trie.put("pre", Boolean.TRUE); - trie.put("prefalse", Boolean.FALSE); - assertEquals(Boolean.TRUE, trie.get("pre")); - assertEquals(Boolean.FALSE, trie.get("prefalse")); - } - - public void testDuplicateAdd() - { - HashTrie trie = new HashTrie(); - - assertNull(trie.put("dup", Boolean.TRUE)); - assertTrue(trie.put("dup", Boolean.FALSE)); - assertFalse(trie.get("dup")); - } - - public void testTwoInsertLongestLookup() - { - HashTrie trie = new HashTrie(); - Entry entry; - - trie.put("true", Boolean.TRUE); - trie.put("true idea", Boolean.TRUE); - trie.put("false", Boolean.FALSE); - - assertNotNull((entry = trie.getLongestMatch("true"))); - assertEquals("true", entry.getKey()); - assertTrue(entry.getValue()); - - assertNotNull((entry = trie.getLongestMatch("false"))); - assertEquals("false", entry.getKey()); - assertFalse(entry.getValue()); - - assertNotNull((entry = trie.getLongestMatch("truer"))); - assertEquals("true", entry.getKey()); - assertTrue(entry.getValue()); - - assertNotNull((entry = trie.getLongestMatch("true to form"))); - assertEquals("true", entry.getKey()); - assertTrue(entry.getValue()); - - assertNotNull((entry = trie.getLongestMatch("false result"))); - assertEquals("false", entry.getKey()); - assertFalse(entry.getValue()); - - assertNull(trie.getLongestMatch("not there")); - assertNull(trie.getLongestMatch("tru")); - assertNull(trie.getLongestMatch("fals")); - } - - public void testContainsKey() - { - HashTrie trie = new HashTrie(); - - trie.put("true", Boolean.TRUE); - trie.put("false", Boolean.FALSE); - assertTrue(trie.containsKey("true")); - assertTrue(trie.containsKey("false")); - assertFalse(trie.containsKey("not there")); - } - - public void testContainsValue() - { - HashTrie trie = new HashTrie(); - - trie.put("one", 1); - trie.put("two", 2); - assertTrue(trie.containsValue(1)); - assertTrue(trie.containsValue(2)); - assertFalse(trie.containsValue(3)); - } - - public void testKeySet() - { - HashTrie trie = new HashTrie(); - HashSet expected = new HashSet(2); - - expected.add("true"); - expected.add("false"); - trie.put("true", Boolean.TRUE); - trie.put("false", Boolean.FALSE); - assertEquals(expected,trie.keySet()); - } - - public void testValues() - { - HashTrie trie = new HashTrie(); - ArrayList actual; - ArrayList expected = new ArrayList(2); - - expected.add(Boolean.TRUE); - expected.add(Boolean.FALSE); - trie.put("true", Boolean.TRUE); - trie.put("false", Boolean.FALSE); - actual = new ArrayList(trie.values()); - Collections.sort(actual); - Collections.sort(expected); - assertEquals(expected,actual); - } - - public void testEntrySet() - { - HashTrie trie = new HashTrie(); - HashMap equivMap = new HashMap(2); - - equivMap.put("true",Boolean.TRUE); - equivMap.put("false",Boolean.FALSE); - trie.put("true", Boolean.TRUE); - trie.put("false", Boolean.FALSE); - assertEquals(equivMap.entrySet(),trie.entrySet()); - } - - public void testEquals() - { - HashTrie trie = new HashTrie(); - HashMap equivMap = new HashMap(2); - - equivMap.put("true",Boolean.TRUE); - equivMap.put("false",Boolean.FALSE); - trie.put("true", Boolean.TRUE); - trie.put("false", Boolean.FALSE); - assertTrue(trie.equals(equivMap)); - } - - public void testHashCode() - { - HashTrie trie = new HashTrie(); - HashMap equivMap = new HashMap(2); - - equivMap.put("true",Boolean.TRUE); - equivMap.put("false",Boolean.FALSE); - trie.put("true", Boolean.TRUE); - trie.put("false", Boolean.FALSE); - assertEquals(equivMap.hashCode(),trie.hashCode()); - } - - /** - * Create a test suite with just this test. - * @return A test swuite with just this test. - */ - public static Test suite() - { - TestSuite suite = new TestSuite(CLASS); - return suite; - } + private static final Class CLASS = HashTrieTest.class; + + public HashTrieTest(String testName) + { + super(testName); + } + + public void testSingleInsertLookup() + { + HashTrie trie = new HashTrie(); + + trie.put("true", Boolean.TRUE); + assertEquals(Boolean.TRUE, trie.get("true")); + assertNull(trie.get("not there")); + assertNull(trie.get("tru")); + assertNull(trie.get("trueX")); + assertEquals("true".length(), trie.getMaxKeyLength()); + } + + public void testEmpty() + { + HashTrie trie = new HashTrie(); + assertNull(trie.get("true")); + assertNull(trie.get("false")); + assertNull(trie.get("")); + assertTrue(trie.getMaxKeyLength()<0); + } + + public void testTwoInsertLookup() + { + HashTrie trie = new HashTrie(); + + trie.put("true", Boolean.TRUE); + trie.put("false", Boolean.FALSE); + assertEquals(Boolean.TRUE, trie.get("true")); + assertEquals(Boolean.FALSE, trie.get("false")); + assertEquals("false".length(),trie.getMaxKeyLength()); + } + + public void testMatchingPrefix() + { + HashTrie trie = new HashTrie(); + + trie.put("pretrue", Boolean.TRUE); + trie.put("prefalse", Boolean.FALSE); + assertEquals(Boolean.TRUE, trie.get("pretrue")); + assertEquals(Boolean.FALSE, trie.get("prefalse")); + } + + public void testPrefixIsValidKey() + { + HashTrie trie = new HashTrie(); + + trie.put("pre", Boolean.TRUE); + trie.put("prefalse", Boolean.FALSE); + assertEquals(Boolean.TRUE, trie.get("pre")); + assertEquals(Boolean.FALSE, trie.get("prefalse")); + } + + public void testDuplicateAdd() + { + HashTrie trie = new HashTrie(); + + assertNull(trie.put("dup", Boolean.TRUE)); + assertTrue(trie.put("dup", Boolean.FALSE)); + assertFalse(trie.get("dup")); + } + + public void testTwoInsertLongestLookup() + { + HashTrie trie = new HashTrie(); + Entry entry; + + trie.put("true", Boolean.TRUE); + trie.put("true idea", Boolean.TRUE); + trie.put("false", Boolean.FALSE); + + assertNotNull((entry = trie.getLongestMatch("true"))); + assertEquals("true", entry.getKey()); + assertTrue(entry.getValue()); + + assertNotNull((entry = trie.getLongestMatch("false"))); + assertEquals("false", entry.getKey()); + assertFalse(entry.getValue()); + + assertNotNull((entry = trie.getLongestMatch("truer"))); + assertEquals("true", entry.getKey()); + assertTrue(entry.getValue()); + + assertNotNull((entry = trie.getLongestMatch("true to form"))); + assertEquals("true", entry.getKey()); + assertTrue(entry.getValue()); + + assertNotNull((entry = trie.getLongestMatch("false result"))); + assertEquals("false", entry.getKey()); + assertFalse(entry.getValue()); + + assertNull(trie.getLongestMatch("not there")); + assertNull(trie.getLongestMatch("tru")); + assertNull(trie.getLongestMatch("fals")); + } + + public void testContainsKey() + { + HashTrie trie = new HashTrie(); + + trie.put("true", Boolean.TRUE); + trie.put("false", Boolean.FALSE); + assertTrue(trie.containsKey("true")); + assertTrue(trie.containsKey("false")); + assertFalse(trie.containsKey("not there")); + } + + public void testContainsValue() + { + HashTrie trie = new HashTrie(); + + trie.put("one", 1); + trie.put("two", 2); + assertTrue(trie.containsValue(1)); + assertTrue(trie.containsValue(2)); + assertFalse(trie.containsValue(3)); + } + + public void testKeySet() + { + HashTrie trie = new HashTrie(); + HashSet expected = new HashSet(2); + + expected.add("true"); + expected.add("false"); + trie.put("true", Boolean.TRUE); + trie.put("false", Boolean.FALSE); + assertEquals(expected,trie.keySet()); + } + + public void testValues() + { + HashTrie trie = new HashTrie(); + ArrayList actual; + ArrayList expected = new ArrayList(2); + + expected.add(Boolean.TRUE); + expected.add(Boolean.FALSE); + trie.put("true", Boolean.TRUE); + trie.put("false", Boolean.FALSE); + actual = new ArrayList(trie.values()); + Collections.sort(actual); + Collections.sort(expected); + assertEquals(expected,actual); + } + + public void testEntrySet() + { + HashTrie trie = new HashTrie(); + HashMap equivMap = new HashMap(2); + + equivMap.put("true",Boolean.TRUE); + equivMap.put("false",Boolean.FALSE); + trie.put("true", Boolean.TRUE); + trie.put("false", Boolean.FALSE); + assertEquals(equivMap.entrySet(),trie.entrySet()); + } + + public void testEquals() + { + HashTrie trie = new HashTrie(); + HashMap equivMap = new HashMap(2); + + equivMap.put("true",Boolean.TRUE); + equivMap.put("false",Boolean.FALSE); + trie.put("true", Boolean.TRUE); + trie.put("false", Boolean.FALSE); + assertTrue(trie.equals(equivMap)); + } + + public void testHashCode() + { + HashTrie trie = new HashTrie(); + HashMap equivMap = new HashMap(2); + + equivMap.put("true",Boolean.TRUE); + equivMap.put("false",Boolean.FALSE); + trie.put("true", Boolean.TRUE); + trie.put("false", Boolean.FALSE); + assertEquals(equivMap.hashCode(),trie.hashCode()); + } + + /** + * Create a test suite with just this test. + * @return A test swuite with just this test. + */ + public static Test suite() + { + TestSuite suite = new TestSuite(CLASS); + return suite; + } } diff --git a/src/test/java/org/owasp/esapi/codecs/PercentCodecTest.java b/src/test/java/org/owasp/esapi/codecs/PercentCodecTest.java index c1b2b7ad8..2946d54ed 100644 --- a/src/test/java/org/owasp/esapi/codecs/PercentCodecTest.java +++ b/src/test/java/org/owasp/esapi/codecs/PercentCodecTest.java @@ -5,12 +5,12 @@ import org.junit.Test; public class PercentCodecTest { - - @Test - public void testPercentDecode(){ - Codec codec = new PercentCodec(); - - String expected = " "; - assertEquals(expected, codec.decode("%20")); - } + + @Test + public void testPercentDecode(){ + Codec codec = new PercentCodec(); + + String expected = " "; + assertEquals(expected, codec.decode("%20")); + } } diff --git a/src/test/java/org/owasp/esapi/codecs/PushBackStringTest.java b/src/test/java/org/owasp/esapi/codecs/PushBackStringTest.java index 2a4ed84e2..61e9bc59a 100644 --- a/src/test/java/org/owasp/esapi/codecs/PushBackStringTest.java +++ b/src/test/java/org/owasp/esapi/codecs/PushBackStringTest.java @@ -6,36 +6,36 @@ public class PushBackStringTest { - @Test - public void testPushbackString() { - PushbackSequence pbs = new PushbackString("012345"); - - pbs.mark(); - assertEquals(0, pbs.index()); - Character first = pbs.next(); - - System.out.println("0x" + Integer.toHexString(first)); - - assertEquals("0", new StringBuilder().appendCodePoint(first).toString()); - } - - @Test - public void testPushbackSequence() { - AbstractPushbackSequence pbs = new PushBackSequenceImpl("12345"); - - pbs.mark(); - assertEquals(0, pbs.index()); - Integer first = pbs.next(); - - System.out.println("0x" + Integer.toHexString(first)); - - assertEquals("&", new StringBuilder().appendCodePoint(first).toString()); - - Integer second = pbs.next(); - - if(second == '#'){ - System.out.printf("[%d]:[%d]\n", second, (int) '#'); - - } - } + @Test + public void testPushbackString() { + PushbackSequence pbs = new PushbackString("012345"); + + pbs.mark(); + assertEquals(0, pbs.index()); + Character first = pbs.next(); + + System.out.println("0x" + Integer.toHexString(first)); + + assertEquals("0", new StringBuilder().appendCodePoint(first).toString()); + } + + @Test + public void testPushbackSequence() { + AbstractPushbackSequence pbs = new PushBackSequenceImpl("12345"); + + pbs.mark(); + assertEquals(0, pbs.index()); + Integer first = pbs.next(); + + System.out.println("0x" + Integer.toHexString(first)); + + assertEquals("&", new StringBuilder().appendCodePoint(first).toString()); + + Integer second = pbs.next(); + + if(second == '#'){ + System.out.printf("[%d]:[%d]\n", second, (int) '#'); + + } + } } diff --git a/src/test/java/org/owasp/esapi/codecs/XMLEntityCodecTest.java b/src/test/java/org/owasp/esapi/codecs/XMLEntityCodecTest.java index 10424c67c..4b3dc56bf 100644 --- a/src/test/java/org/owasp/esapi/codecs/XMLEntityCodecTest.java +++ b/src/test/java/org/owasp/esapi/codecs/XMLEntityCodecTest.java @@ -25,229 +25,229 @@ public class XMLEntityCodecTest extends TestCase { - private static final char[] EMPTY_CHAR_ARRAY = new char[0]; - private static final String ALPHA_NUMERIC_STR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - private static final String UNENCODED_STR = ALPHA_NUMERIC_STR + " \t"; - private static final Set UNENCODED_SET = CollectionsUtil.strToUnmodifiableSet(UNENCODED_STR); - private XMLEntityCodec codec = null; - - protected void setUp() - { - codec = new XMLEntityCodec(); - } - - protected void tearDown() - { - codec = null; - } - - public void testEncodeUnencoded() - { - StringBuilder sb = new StringBuilder("AB_YZ"); - String str; - - for(char ch : UNENCODED_SET) - { - sb.setCharAt(2,ch); - str = sb.toString(); - assertEquals(str, codec.encode(EMPTY_CHAR_ARRAY, str)); - } - } - - public void testEncodeOthers() - { - StringBuilder inSb = new StringBuilder("AB_YZ"); - StringBuilder outSb = new StringBuilder("AB&#x"); - String in; - String expected; - String result; - int outSbBaseLen = outSb.length(); - String out; - - for(int c=Character.MIN_VALUE;c<=Character.MAX_VALUE;c++) - { - char ch = (char)c; - if(UNENCODED_SET.contains(ch)) - continue; - inSb.setCharAt(2,ch); - in = inSb.toString(); - outSb.append(Integer.toHexString(c)); - outSb.append(";YZ"); - expected = outSb.toString(); - result = codec.encode(EMPTY_CHAR_ARRAY,in); - assertEquals(expected, result); - outSb.setLength(outSbBaseLen); - } - } - - public void testDecodeUnencoded() - { - StringBuilder sb = new StringBuilder("AB_YZ"); - String str; - - for(char ch : UNENCODED_SET) - { - sb.setCharAt(2,ch); - str = sb.toString(); - assertEquals(str, codec.decode(str)); - } - } - - public void testDecodeHex() - { - StringBuilder expectedSb = new StringBuilder("AB_YZ"); - StringBuilder inSb = new StringBuilder("AB&#x"); - String in; - String expected; - String result; - int inSbBaseLen = inSb.length(); - - for(int c=Character.MIN_VALUE;c<=Character.MAX_VALUE;c++) - { - char ch = (char)c; - expectedSb.setCharAt(2,ch); - expected = expectedSb.toString(); - inSb.append(Integer.toHexString(c)); - inSb.append(";YZ"); - in = inSb.toString(); - result = codec.decode(in); - assertEquals(expected, result); - inSb.setLength(inSbBaseLen); - } - } - - public void testDecodeDec() - { - StringBuilder expectedSb = new StringBuilder("AB_YZ"); - StringBuilder inSb = new StringBuilder("AB&#"); - String in; - String expected; - String result; - int inSbBaseLen = inSb.length(); - - for(int c=Character.MIN_VALUE;c<=Character.MAX_VALUE;c++) - { - char ch = (char)c; - expectedSb.setCharAt(2,ch); - expected = expectedSb.toString(); - inSb.append(Integer.toString(c)); - inSb.append(";YZ"); - in = inSb.toString(); - result = codec.decode(in); - assertEquals(expected, result); - inSb.setLength(inSbBaseLen); - } - } - - public void testDecodeLt() - { - String in = "AB<YZ"; - String expected = "AB UNENCODED_SET = CollectionsUtil.strToUnmodifiableSet(UNENCODED_STR); + private XMLEntityCodec codec = null; + + protected void setUp() + { + codec = new XMLEntityCodec(); + } + + protected void tearDown() + { + codec = null; + } + + public void testEncodeUnencoded() + { + StringBuilder sb = new StringBuilder("AB_YZ"); + String str; + + for(char ch : UNENCODED_SET) + { + sb.setCharAt(2,ch); + str = sb.toString(); + assertEquals(str, codec.encode(EMPTY_CHAR_ARRAY, str)); + } + } + + public void testEncodeOthers() + { + StringBuilder inSb = new StringBuilder("AB_YZ"); + StringBuilder outSb = new StringBuilder("AB&#x"); + String in; + String expected; + String result; + int outSbBaseLen = outSb.length(); + String out; + + for(int c=Character.MIN_VALUE;c<=Character.MAX_VALUE;c++) + { + char ch = (char)c; + if(UNENCODED_SET.contains(ch)) + continue; + inSb.setCharAt(2,ch); + in = inSb.toString(); + outSb.append(Integer.toHexString(c)); + outSb.append(";YZ"); + expected = outSb.toString(); + result = codec.encode(EMPTY_CHAR_ARRAY,in); + assertEquals(expected, result); + outSb.setLength(outSbBaseLen); + } + } + + public void testDecodeUnencoded() + { + StringBuilder sb = new StringBuilder("AB_YZ"); + String str; + + for(char ch : UNENCODED_SET) + { + sb.setCharAt(2,ch); + str = sb.toString(); + assertEquals(str, codec.decode(str)); + } + } + + public void testDecodeHex() + { + StringBuilder expectedSb = new StringBuilder("AB_YZ"); + StringBuilder inSb = new StringBuilder("AB&#x"); + String in; + String expected; + String result; + int inSbBaseLen = inSb.length(); + + for(int c=Character.MIN_VALUE;c<=Character.MAX_VALUE;c++) + { + char ch = (char)c; + expectedSb.setCharAt(2,ch); + expected = expectedSb.toString(); + inSb.append(Integer.toHexString(c)); + inSb.append(";YZ"); + in = inSb.toString(); + result = codec.decode(in); + assertEquals(expected, result); + inSb.setLength(inSbBaseLen); + } + } + + public void testDecodeDec() + { + StringBuilder expectedSb = new StringBuilder("AB_YZ"); + StringBuilder inSb = new StringBuilder("AB&#"); + String in; + String expected; + String result; + int inSbBaseLen = inSb.length(); + + for(int c=Character.MIN_VALUE;c<=Character.MAX_VALUE;c++) + { + char ch = (char)c; + expectedSb.setCharAt(2,ch); + expected = expectedSb.toString(); + inSb.append(Integer.toString(c)); + inSb.append(";YZ"); + in = inSb.toString(); + result = codec.decode(in); + assertEquals(expected, result); + inSb.setLength(inSbBaseLen); + } + } + + public void testDecodeLt() + { + String in = "AB<YZ"; + String expected = "AB 0 ); - cipherSpec = new CipherSpec(myIV); - assertTrue( cipherSpec.getKeySize() == - ESAPI.securityConfiguration().getEncryptionKeyLength() ); - assertTrue( cipherSpec.getCipherTransformation().equals( - ESAPI.securityConfiguration().getCipherTransformation() ) ); - } + /** Test CipherSpec(final byte[] iv) */ + @Test public void testCipherSpecByteArray() { + assertTrue( myIV != null ); + assertTrue( myIV.length > 0 ); + cipherSpec = new CipherSpec(myIV); + assertTrue( cipherSpec.getKeySize() == + ESAPI.securityConfiguration().getEncryptionKeyLength() ); + assertTrue( cipherSpec.getCipherTransformation().equals( + ESAPI.securityConfiguration().getCipherTransformation() ) ); + } - /** Test CipherSpec() */ - @Test public void testCipherSpec() { - cipherSpec = new CipherSpec( dfltECBCipher ); - assertTrue( cipherSpec.getCipherTransformation().equals("AES/ECB/NoPadding") ); - assertTrue( cipherSpec.getIV() == null ); - - cipherSpec = new CipherSpec(dfltOtherCipher); - assertTrue( cipherSpec.getCipherMode().equals("OFB8") ); - } + /** Test CipherSpec() */ + @Test public void testCipherSpec() { + cipherSpec = new CipherSpec( dfltECBCipher ); + assertTrue( cipherSpec.getCipherTransformation().equals("AES/ECB/NoPadding") ); + assertTrue( cipherSpec.getIV() == null ); + + cipherSpec = new CipherSpec(dfltOtherCipher); + assertTrue( cipherSpec.getCipherMode().equals("OFB8") ); + } - /** Test setCipherTransformation(String cipherXform) */ - @Test public void testSetCipherTransformation() { - cipherSpec = new CipherSpec(); - cipherSpec.setCipherTransformation("AlgName/Mode/Padding"); - cipherSpec.getCipherAlgorithm().equals("AlgName/Mode/Padding"); - - try { - // Don't use null here as compiling JUnit tests disables assertion - // checking so we get a NullPointerException here instead. - cipherSpec.setCipherTransformation(""); // Throws IllegalArgumentException - } catch (IllegalArgumentException e) { - assertTrue(true); // Doesn't work w/ @Test(expected=IllegalArgumentException.class) - } - } + /** Test setCipherTransformation(String cipherXform) */ + @Test public void testSetCipherTransformation() { + cipherSpec = new CipherSpec(); + cipherSpec.setCipherTransformation("AlgName/Mode/Padding"); + cipherSpec.getCipherAlgorithm().equals("AlgName/Mode/Padding"); + + try { + // Don't use null here as compiling JUnit tests disables assertion + // checking so we get a NullPointerException here instead. + cipherSpec.setCipherTransformation(""); // Throws IllegalArgumentException + } catch (IllegalArgumentException e) { + assertTrue(true); // Doesn't work w/ @Test(expected=IllegalArgumentException.class) + } + } - /** Test getCipherTransformation() */ - @Test public void testGetCipherTransformation() { - assertTrue( (new CipherSpec()).getCipherTransformation().equals("AES/CBC/PKCS5Padding") ); - } + /** Test getCipherTransformation() */ + @Test public void testGetCipherTransformation() { + assertTrue( (new CipherSpec()).getCipherTransformation().equals("AES/CBC/PKCS5Padding") ); + } - /** Test setKeySize() */ - @Test public void testSetKeySize() { - assertTrue( (new CipherSpec()).setKeySize(56).getKeySize() == 56 ); - } + /** Test setKeySize() */ + @Test public void testSetKeySize() { + assertTrue( (new CipherSpec()).setKeySize(56).getKeySize() == 56 ); + } - /** Test getKeySize() */ - @Test public void testGetKeySize() { - assertTrue( (new CipherSpec()).getKeySize() == - ESAPI.securityConfiguration().getEncryptionKeyLength() ); - } + /** Test getKeySize() */ + @Test public void testGetKeySize() { + assertTrue( (new CipherSpec()).getKeySize() == + ESAPI.securityConfiguration().getEncryptionKeyLength() ); + } - /** Test setBlockSize() */ - @Test public void testSetBlockSize() { - try { - cipherSpec.setBlockSize(0); // Throws IllegalArgumentException - } catch (IllegalArgumentException e) { - assertTrue(true); - } - try { - cipherSpec.setBlockSize(-1); // Throws IllegalArgumentException - } catch (IllegalArgumentException e) { - assertTrue(true); - } - assertTrue( cipherSpec.setBlockSize(4).getBlockSize() == 4 ); - } + /** Test setBlockSize() */ + @Test public void testSetBlockSize() { + try { + cipherSpec.setBlockSize(0); // Throws IllegalArgumentException + } catch (IllegalArgumentException e) { + assertTrue(true); + } + try { + cipherSpec.setBlockSize(-1); // Throws IllegalArgumentException + } catch (IllegalArgumentException e) { + assertTrue(true); + } + assertTrue( cipherSpec.setBlockSize(4).getBlockSize() == 4 ); + } - /** Test getBlockSize() */ - @Test public void testGetBlockSize() { - assertTrue( cipherSpec.getBlockSize() == 8 ); - } + /** Test getBlockSize() */ + @Test public void testGetBlockSize() { + assertTrue( cipherSpec.getBlockSize() == 8 ); + } - /** Test getCipherAlgorithm() */ - @Test public void testGetCipherAlgorithm() { - assertTrue( cipherSpec.getCipherAlgorithm().equals("Blowfish") ); - } + /** Test getCipherAlgorithm() */ + @Test public void testGetCipherAlgorithm() { + assertTrue( cipherSpec.getCipherAlgorithm().equals("Blowfish") ); + } - /** Test getCipherMode */ - @Test public void testGetCipherMode() { - assertTrue( cipherSpec.getCipherMode().equals("OFB8") ); - } + /** Test getCipherMode */ + @Test public void testGetCipherMode() { + assertTrue( cipherSpec.getCipherMode().equals("OFB8") ); + } - /** Test getPaddingScheme() */ - @Test public void testGetPaddingScheme() { - assertTrue( cipherSpec.getPaddingScheme().equals("PKCS5Padding") ); - } + /** Test getPaddingScheme() */ + @Test public void testGetPaddingScheme() { + assertTrue( cipherSpec.getPaddingScheme().equals("PKCS5Padding") ); + } - /** Test setIV() */ - @Test public void testSetIV() { - try { - // Test that ECB mode allows a null IV - cipherSpec = new CipherSpec(dfltECBCipher); + /** Test setIV() */ + @Test public void testSetIV() { + try { + // Test that ECB mode allows a null IV + cipherSpec = new CipherSpec(dfltECBCipher); assertTrue( cipherSpec.getCipherMode().equals("ECB") ); - cipherSpec.setIV(null); - assertTrue(true); - } catch ( IllegalArgumentException e) { - assertFalse("Test failed; unexpected exception", false); - } - try { - // Test that CBC mode does allows a null IV - cipherSpec = new CipherSpec(dfltAESCipher); - cipherSpec.setIV(null); - assertFalse("Test failed; Expected exception not thrown", false); - } catch ( IllegalArgumentException e) { - assertTrue(true); - } - } + cipherSpec.setIV(null); + assertTrue(true); + } catch ( IllegalArgumentException e) { + assertFalse("Test failed; unexpected exception", false); + } + try { + // Test that CBC mode does allows a null IV + cipherSpec = new CipherSpec(dfltAESCipher); + cipherSpec.setIV(null); + assertFalse("Test failed; Expected exception not thrown", false); + } catch ( IllegalArgumentException e) { + assertTrue(true); + } + } - /** Test requiresIV() */ - @Test public void testRequiresIV() { - assertTrue( (new CipherSpec(dfltECBCipher)).requiresIV() == false ); - cipherSpec = new CipherSpec(dfltAESCipher); - assertTrue( cipherSpec.getCipherMode().equals("ECB") ); - assertTrue( cipherSpec.requiresIV() == false ); - assertTrue( new CipherSpec(dfltOtherCipher).requiresIV() ); - } - - /** Test serialization */ - @Test public void testSerialization() { + /** Test requiresIV() */ + @Test public void testRequiresIV() { + assertTrue( (new CipherSpec(dfltECBCipher)).requiresIV() == false ); + cipherSpec = new CipherSpec(dfltAESCipher); + assertTrue( cipherSpec.getCipherMode().equals("ECB") ); + assertTrue( cipherSpec.requiresIV() == false ); + assertTrue( new CipherSpec(dfltOtherCipher).requiresIV() ); + } + + /** Test serialization */ + @Test public void testSerialization() { String filename = "cipherspec.ser"; File serializedFile = new File(filename); boolean success = false; @@ -234,7 +234,7 @@ public class CipherSpecTest extends TestCase { // check that cipherSpec and restoredCipherSpec are equal. Just // compare them via their string representations. assertEquals("Serialized restored CipherSpec differs from saved CipherSpec", - cipherSpec.toString(), restoredCipherSpec.toString() ); + cipherSpec.toString(), restoredCipherSpec.toString() ); success = true; } catch(IOException ex) { @@ -257,8 +257,8 @@ public class CipherSpecTest extends TestCase { } } } - } - + } + /** * Run all the test cases in this suite. * This is to allow running from {@code org.owasp.esapi.AllTests}. diff --git a/src/test/java/org/owasp/esapi/crypto/CipherTextSerializerTest.java b/src/test/java/org/owasp/esapi/crypto/CipherTextSerializerTest.java index 9f86b9fb7..fcf5be73e 100644 --- a/src/test/java/org/owasp/esapi/crypto/CipherTextSerializerTest.java +++ b/src/test/java/org/owasp/esapi/crypto/CipherTextSerializerTest.java @@ -18,7 +18,7 @@ public class CipherTextSerializerTest { private Cipher encryptor = null; private IvParameterSpec ivSpec = null; // Note: FindBugs reports false positive // about this being unread field. See - // testAsSerializedByteArray(). + // testAsSerializedByteArray(). @BeforeClass public static void setUpBeforeClass() throws Exception { @@ -38,12 +38,12 @@ public void setUp() throws Exception { @After public void tearDown() throws Exception { - System.out.flush(); + System.out.flush(); } @Test public final void testAsSerializedByteArray() { - System.out.println("CipherTextSerializerTest.testAsSerializedByteArray() ..."); + System.out.println("CipherTextSerializerTest.testAsSerializedByteArray() ..."); CipherSpec cipherSpec = new CipherSpec(encryptor, 128); cipherSpec.setIV(ivSpec.getIV()); SecretKey key; @@ -68,7 +68,7 @@ public final void testAsSerializedByteArray() { @Test public final void testAsCipherText() { try { - System.out.println("CipherTextSerializerTest.testAsCipherText() ..."); + System.out.println("CipherTextSerializerTest.testAsCipherText() ..."); CipherText ct = ESAPI.encryptor().encrypt( new PlainText("Hello") ); CipherTextSerializer cts = new CipherTextSerializer( ct ); CipherText result = cts.asCipherText(); diff --git a/src/test/java/org/owasp/esapi/crypto/CipherTextTest.java b/src/test/java/org/owasp/esapi/crypto/CipherTextTest.java index b3a6b5587..8e58498d4 100644 --- a/src/test/java/org/owasp/esapi/crypto/CipherTextTest.java +++ b/src/test/java/org/owasp/esapi/crypto/CipherTextTest.java @@ -23,7 +23,7 @@ public class CipherTextTest { - private CipherSpec cipherSpec_ = null; + private CipherSpec cipherSpec_ = null; private Cipher encryptor = null; private Cipher decryptor = null; private IvParameterSpec ivSpec = null; @@ -31,173 +31,173 @@ public class CipherTextTest { public TemporaryFolder tempFolder = new TemporaryFolder(); - @Before - public void setUp() throws Exception { + @Before + public void setUp() throws Exception { encryptor = Cipher.getInstance("AES/CBC/PKCS5Padding"); decryptor = Cipher.getInstance("AES/CBC/PKCS5Padding"); byte[] ivBytes = null; ivBytes = ESAPI.randomizer().getRandomBytes(encryptor.getBlockSize()); ivSpec = new IvParameterSpec(ivBytes); - } + } - /** Test the default CTOR */ - @Test - public final void testCipherText() { - CipherText ct = new CipherText(); + /** Test the default CTOR */ + @Test + public final void testCipherText() { + CipherText ct = new CipherText(); - cipherSpec_ = new CipherSpec(); - assertTrue( ct.getCipherTransformation().equals( cipherSpec_.getCipherTransformation())); - assertTrue( ct.getBlockSize() == cipherSpec_.getBlockSize() ); - } + cipherSpec_ = new CipherSpec(); + assertTrue( ct.getCipherTransformation().equals( cipherSpec_.getCipherTransformation())); + assertTrue( ct.getBlockSize() == cipherSpec_.getBlockSize() ); + } - @Test - public final void testCipherTextCipherSpec() { - cipherSpec_ = new CipherSpec("DESede/OFB8/NoPadding", 112); - CipherText ct = new CipherText( cipherSpec_ ); - assertTrue( ct.getRawCipherText() == null ); - assertTrue( ct.getCipherAlgorithm().equals("DESede") ); - assertTrue( ct.getKeySize() == cipherSpec_.getKeySize() ); - } + @Test + public final void testCipherTextCipherSpec() { + cipherSpec_ = new CipherSpec("DESede/OFB8/NoPadding", 112); + CipherText ct = new CipherText( cipherSpec_ ); + assertTrue( ct.getRawCipherText() == null ); + assertTrue( ct.getCipherAlgorithm().equals("DESede") ); + assertTrue( ct.getKeySize() == cipherSpec_.getKeySize() ); + } - @Test - public final void testCipherTextCipherSpecByteArray() - { - try { - CipherSpec cipherSpec = new CipherSpec(encryptor, 128); - cipherSpec.setIV(ivSpec.getIV()); - SecretKey key = - CryptoHelper.generateSecretKey(cipherSpec.getCipherAlgorithm(), 128); - encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec); - byte[] raw = encryptor.doFinal("Hello".getBytes("UTF8")); - CipherText ct = new CipherText(cipherSpec, raw); - assertTrue( ct != null ); - byte[] ctRaw = ct.getRawCipherText(); - assertTrue( ctRaw != null ); - assertArrayEquals(raw, ctRaw); - assertTrue( ct.getCipherTransformation().equals(cipherSpec.getCipherTransformation()) );; - assertTrue( ct.getCipherAlgorithm().equals(cipherSpec.getCipherAlgorithm()) ); - assertTrue( ct.getPaddingScheme().equals(cipherSpec.getPaddingScheme()) ); - assertTrue( ct.getBlockSize() == cipherSpec.getBlockSize() ); - assertTrue( ct.getKeySize() == cipherSpec.getKeySize() ); - byte[] ctIV = ct.getIV(); - byte[] csIV = cipherSpec.getIV(); - assertArrayEquals(ctIV, csIV); - } catch( Exception ex) { - // As far as test coverage goes, we really don't want this to be covered. - fail("Caught unexpected exception: " + ex.getClass().getName() + - "; exception message was: " + ex.getMessage()); - } - } + @Test + public final void testCipherTextCipherSpecByteArray() + { + try { + CipherSpec cipherSpec = new CipherSpec(encryptor, 128); + cipherSpec.setIV(ivSpec.getIV()); + SecretKey key = + CryptoHelper.generateSecretKey(cipherSpec.getCipherAlgorithm(), 128); + encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec); + byte[] raw = encryptor.doFinal("Hello".getBytes("UTF8")); + CipherText ct = new CipherText(cipherSpec, raw); + assertTrue( ct != null ); + byte[] ctRaw = ct.getRawCipherText(); + assertTrue( ctRaw != null ); + assertArrayEquals(raw, ctRaw); + assertTrue( ct.getCipherTransformation().equals(cipherSpec.getCipherTransformation()) );; + assertTrue( ct.getCipherAlgorithm().equals(cipherSpec.getCipherAlgorithm()) ); + assertTrue( ct.getPaddingScheme().equals(cipherSpec.getPaddingScheme()) ); + assertTrue( ct.getBlockSize() == cipherSpec.getBlockSize() ); + assertTrue( ct.getKeySize() == cipherSpec.getKeySize() ); + byte[] ctIV = ct.getIV(); + byte[] csIV = cipherSpec.getIV(); + assertArrayEquals(ctIV, csIV); + } catch( Exception ex) { + // As far as test coverage goes, we really don't want this to be covered. + fail("Caught unexpected exception: " + ex.getClass().getName() + + "; exception message was: " + ex.getMessage()); + } + } - @Test - public final void testDecryptionUsingCipherText() { - try { - CipherSpec cipherSpec = new CipherSpec(encryptor, 128); - cipherSpec.setIV(ivSpec.getIV()); - assertTrue( cipherSpec.getIV() != null ); - assertTrue( cipherSpec.getIV().length > 0 ); - SecretKey key = - CryptoHelper.generateSecretKey(cipherSpec.getCipherAlgorithm(), 128); - encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec); - byte[] ctraw = encryptor.doFinal("Hello".getBytes("UTF8")); - CipherText ct = new CipherText(cipherSpec, ctraw); - assertTrue( ct.getCipherMode().equals("CBC") ); - assertTrue( ct.requiresIV() ); // CBC mode requires an IV. - String b64ctraw = ct.getBase64EncodedRawCipherText(); - assertTrue( b64ctraw != null); - assertArrayEquals( ESAPI.encoder().decodeFromBase64(b64ctraw), ctraw ); - decryptor.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ct.getIV())); - byte[] ptraw = decryptor.doFinal(ESAPI.encoder().decodeFromBase64(b64ctraw)); - assertTrue( ptraw != null ); - assertTrue( ptraw.length > 0 ); - String plaintext = new String( ptraw, "UTF-8"); - assertTrue( plaintext.equals("Hello") ); - assertArrayEquals( ct.getRawCipherText(), ctraw ); - - byte[] ivAndRaw = ESAPI.encoder().decodeFromBase64( ct.getEncodedIVCipherText() ); - assertTrue( ivAndRaw.length > ctraw.length ); - assertTrue( ct.getBlockSize() == ( ivAndRaw.length - ctraw.length ) ); - } catch( Exception ex) { - // Note: FindBugs reports a false positive here... - // REC_CATCH_EXCEPTION: Exception is caught when Exception is not thrown - // but exceptions really can be thrown. This probably is because FindBugs - // examines the byte-code rather than the source code. However "fixing" this - // so that it doesn't complain will make the test much more complicated as there - // are about 3 or 4 different exception types. - // - // On a completely different note, as far as test coverage metrics goes, - // we really don't care if this is covered or nit as it is not our intent - // to be causing exceptions here. - ex.printStackTrace(System.err); - fail("Caught unexpected exception: " + ex.getClass().getName() + - "; exception message was: " + ex.getMessage()); - } - } + @Test + public final void testDecryptionUsingCipherText() { + try { + CipherSpec cipherSpec = new CipherSpec(encryptor, 128); + cipherSpec.setIV(ivSpec.getIV()); + assertTrue( cipherSpec.getIV() != null ); + assertTrue( cipherSpec.getIV().length > 0 ); + SecretKey key = + CryptoHelper.generateSecretKey(cipherSpec.getCipherAlgorithm(), 128); + encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec); + byte[] ctraw = encryptor.doFinal("Hello".getBytes("UTF8")); + CipherText ct = new CipherText(cipherSpec, ctraw); + assertTrue( ct.getCipherMode().equals("CBC") ); + assertTrue( ct.requiresIV() ); // CBC mode requires an IV. + String b64ctraw = ct.getBase64EncodedRawCipherText(); + assertTrue( b64ctraw != null); + assertArrayEquals( ESAPI.encoder().decodeFromBase64(b64ctraw), ctraw ); + decryptor.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ct.getIV())); + byte[] ptraw = decryptor.doFinal(ESAPI.encoder().decodeFromBase64(b64ctraw)); + assertTrue( ptraw != null ); + assertTrue( ptraw.length > 0 ); + String plaintext = new String( ptraw, "UTF-8"); + assertTrue( plaintext.equals("Hello") ); + assertArrayEquals( ct.getRawCipherText(), ctraw ); + + byte[] ivAndRaw = ESAPI.encoder().decodeFromBase64( ct.getEncodedIVCipherText() ); + assertTrue( ivAndRaw.length > ctraw.length ); + assertTrue( ct.getBlockSize() == ( ivAndRaw.length - ctraw.length ) ); + } catch( Exception ex) { + // Note: FindBugs reports a false positive here... + // REC_CATCH_EXCEPTION: Exception is caught when Exception is not thrown + // but exceptions really can be thrown. This probably is because FindBugs + // examines the byte-code rather than the source code. However "fixing" this + // so that it doesn't complain will make the test much more complicated as there + // are about 3 or 4 different exception types. + // + // On a completely different note, as far as test coverage metrics goes, + // we really don't care if this is covered or nit as it is not our intent + // to be causing exceptions here. + ex.printStackTrace(System.err); + fail("Caught unexpected exception: " + ex.getClass().getName() + + "; exception message was: " + ex.getMessage()); + } + } - @Test - public final void testMIC() { - try { - CipherSpec cipherSpec = new CipherSpec(encryptor, 128); - cipherSpec.setIV(ivSpec.getIV()); - SecretKey key = - CryptoHelper.generateSecretKey(cipherSpec.getCipherAlgorithm(), 128); - encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec); - byte[] ctraw = encryptor.doFinal("Hello".getBytes("UTF8")); - CipherText ct = new CipherText(cipherSpec, ctraw); - assertTrue( ct.getIV() != null && ct.getIV().length > 0 ); - SecretKey authKey = CryptoHelper.computeDerivedKey(key, key.getEncoded().length * 8, "authenticity"); - ct.computeAndStoreMAC( authKey ); - try { - ct.setIVandCiphertext(ivSpec.getIV(), ctraw); // Expected to log & throw. - } catch( Exception ex ) { - assertTrue( ex instanceof EncryptionException ); - } - try { - ct.setCiphertext(ctraw); // Expected to log and throw message about - // not being able to store raw ciphertext. - } catch( Exception ex ) { - assertTrue( ex instanceof EncryptionException ); - } - decryptor.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec( ct.getIV() ) ); - byte[] ptraw = decryptor.doFinal( ct.getRawCipherText() ); - assertTrue( ptraw != null && ptraw.length > 0 ); - ct.validateMAC( authKey ); - } catch( Exception ex) { - // As far as test coverage goes, we really don't want this to be covered. - ex.printStackTrace(System.err); - fail("Caught unexpected exception: " + ex.getClass().getName() + - "; exception message was: " + ex.getMessage()); - } - } + @Test + public final void testMIC() { + try { + CipherSpec cipherSpec = new CipherSpec(encryptor, 128); + cipherSpec.setIV(ivSpec.getIV()); + SecretKey key = + CryptoHelper.generateSecretKey(cipherSpec.getCipherAlgorithm(), 128); + encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec); + byte[] ctraw = encryptor.doFinal("Hello".getBytes("UTF8")); + CipherText ct = new CipherText(cipherSpec, ctraw); + assertTrue( ct.getIV() != null && ct.getIV().length > 0 ); + SecretKey authKey = CryptoHelper.computeDerivedKey(key, key.getEncoded().length * 8, "authenticity"); + ct.computeAndStoreMAC( authKey ); + try { + ct.setIVandCiphertext(ivSpec.getIV(), ctraw); // Expected to log & throw. + } catch( Exception ex ) { + assertTrue( ex instanceof EncryptionException ); + } + try { + ct.setCiphertext(ctraw); // Expected to log and throw message about + // not being able to store raw ciphertext. + } catch( Exception ex ) { + assertTrue( ex instanceof EncryptionException ); + } + decryptor.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec( ct.getIV() ) ); + byte[] ptraw = decryptor.doFinal( ct.getRawCipherText() ); + assertTrue( ptraw != null && ptraw.length > 0 ); + ct.validateMAC( authKey ); + } catch( Exception ex) { + // As far as test coverage goes, we really don't want this to be covered. + ex.printStackTrace(System.err); + fail("Caught unexpected exception: " + ex.getClass().getName() + + "; exception message was: " + ex.getMessage()); + } + } - /** Test portable serialization. */ - @Test public final void testPortableSerialization() throws Exception{ - System.out.println("CipherTextTest.testPortableSerialization()starting..."); - String filename = "ciphertext-portable.ser"; - File serializedFile = tempFolder.newFile(filename); - + /** Test portable serialization. */ + @Test public final void testPortableSerialization() throws Exception{ + System.out.println("CipherTextTest.testPortableSerialization()starting..."); + String filename = "ciphertext-portable.ser"; + File serializedFile = tempFolder.newFile(filename); + - int keySize = 128; - if ( CryptoPolicy.isUnlimitedStrengthCryptoAvailable() ) { - keySize = 256; - } - CipherSpec cipherSpec = new CipherSpec(encryptor, keySize); - cipherSpec.setIV(ivSpec.getIV()); - SecretKey key; - try { - key = CryptoHelper.generateSecretKey(cipherSpec.getCipherAlgorithm(), keySize); + int keySize = 128; + if ( CryptoPolicy.isUnlimitedStrengthCryptoAvailable() ) { + keySize = 256; + } + CipherSpec cipherSpec = new CipherSpec(encryptor, keySize); + cipherSpec.setIV(ivSpec.getIV()); + SecretKey key; + try { + key = CryptoHelper.generateSecretKey(cipherSpec.getCipherAlgorithm(), keySize); - encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec); - byte[] raw = encryptor.doFinal("This is my secret message!!!".getBytes("UTF8")); - CipherText ciphertext = new CipherText(cipherSpec, raw); - KeyDerivationFunction kdf = new KeyDerivationFunction( KeyDerivationFunction.PRF_ALGORITHMS.HmacSHA1 ); - SecretKey authKey = kdf.computeDerivedKey(key, key.getEncoded().length * 8, "authenticity"); - ciphertext.computeAndStoreMAC( authKey ); + encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec); + byte[] raw = encryptor.doFinal("This is my secret message!!!".getBytes("UTF8")); + CipherText ciphertext = new CipherText(cipherSpec, raw); + KeyDerivationFunction kdf = new KeyDerivationFunction( KeyDerivationFunction.PRF_ALGORITHMS.HmacSHA1 ); + SecretKey authKey = kdf.computeDerivedKey(key, key.getEncoded().length * 8, "authenticity"); + ciphertext.computeAndStoreMAC( authKey ); // System.err.println("Original ciphertext being serialized: " + ciphertext); - byte[] serializedBytes = ciphertext.asPortableSerializedByteArray(); - - FileOutputStream fos = new FileOutputStream(serializedFile); + byte[] serializedBytes = ciphertext.asPortableSerializedByteArray(); + + FileOutputStream fos = new FileOutputStream(serializedFile); fos.write(serializedBytes); // Note: FindBugs complains that this test may fail to close // the fos output stream. We don't really care. @@ -221,8 +221,8 @@ public final void testMIC() { CipherText restoredCipherText = CipherText.fromPortableSerializedBytes(bytes); // System.err.println("Restored ciphertext: " + restoredCipherText); assertTrue( ciphertext.equals(restoredCipherText)); - } catch (EncryptionException e) { - Assert.fail("Caught EncryptionException: " + e); + } catch (EncryptionException e) { + Assert.fail("Caught EncryptionException: " + e); } catch (FileNotFoundException e) { Assert.fail("Caught FileNotFoundException: " + e); } catch (IOException e) { @@ -233,16 +233,16 @@ public final void testMIC() { // FindBugs complains that we are ignoring this return value. We really don't care. serializedFile.delete(); } - } - - /** Test portable serialization for backward compatibility with ESAPI 2.0. */ - @Test public final void testPortableSerializationBackwardCompatibility() { - System.out.println("testPortableSerializationBackwardCompatibility()starting..."); - String filename = "src/test/resources/ESAPI2.0-ciphertext-portable.ser"; // Do NOT remove - File serializedFile = new File(filename); + } + + /** Test portable serialization for backward compatibility with ESAPI 2.0. */ + @Test public final void testPortableSerializationBackwardCompatibility() { + System.out.println("testPortableSerializationBackwardCompatibility()starting..."); + String filename = "src/test/resources/ESAPI2.0-ciphertext-portable.ser"; // Do NOT remove + File serializedFile = new File(filename); - try { - // String expectedMsg = "This is my secret message!!!"; + try { + // String expectedMsg = "This is my secret message!!!"; // NOTE: FindBugs complains about this (OS_OPEN_STREAM). It apparently // is too lame to know that 'fis.read()' is a serious side-effect. @@ -255,8 +255,8 @@ public final void testMIC() { CipherText restoredCipherText = CipherText.fromPortableSerializedBytes(bytes); assertTrue( restoredCipherText != null ); int retrievedKdfVersion = restoredCipherText.getKDFVersion(); - } catch (EncryptionException e) { - Assert.fail("Caught EncryptionException: " + e); + } catch (EncryptionException e) { + Assert.fail("Caught EncryptionException: " + e); } catch (FileNotFoundException e) { Assert.fail("Caught FileNotFoundException: " + e); } catch (IOException e) { @@ -264,24 +264,24 @@ public final void testMIC() { } catch (Exception e) { Assert.fail("Caught Exception: " + e); } finally { - ; // Do NOT delete the file. + ; // Do NOT delete the file. } - } - - /** Test Java serialization. */ - @Test public final void testJavaSerialization() { + } + + /** Test Java serialization. */ + @Test public final void testJavaSerialization() { String filename = "ciphertext.ser"; try { File serializedFile = tempFolder.newFile(filename); CipherSpec cipherSpec = new CipherSpec(encryptor, 128); - cipherSpec.setIV(ivSpec.getIV()); - SecretKey key = - CryptoHelper.generateSecretKey(cipherSpec.getCipherAlgorithm(), 128); - encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec); - byte[] raw = encryptor.doFinal("This is my secret message!!!".getBytes("UTF8")); - CipherText ciphertext = new CipherText(cipherSpec, raw); + cipherSpec.setIV(ivSpec.getIV()); + SecretKey key = + CryptoHelper.generateSecretKey(cipherSpec.getCipherAlgorithm(), 128); + encryptor.init(Cipher.ENCRYPT_MODE, key, ivSpec); + byte[] raw = encryptor.doFinal("This is my secret message!!!".getBytes("UTF8")); + CipherText ciphertext = new CipherText(cipherSpec, raw); FileOutputStream fos = new FileOutputStream(serializedFile); ObjectOutputStream out = new ObjectOutputStream(fos); @@ -299,12 +299,12 @@ public final void testMIC() { // multiple checks. (Hmmm... maybe overriding equals() and hashCode() // is in order???) assertEquals("1: Serialized restored CipherText differs from saved CipherText", - ciphertext.toString(), restoredCipherText.toString()); + ciphertext.toString(), restoredCipherText.toString()); assertArrayEquals("2: Serialized restored CipherText differs from saved CipherText", - ciphertext.getIV(), restoredCipherText.getIV()); + ciphertext.getIV(), restoredCipherText.getIV()); assertEquals("3: Serialized restored CipherText differs from saved CipherText", - ciphertext.getBase64EncodedRawCipherText(), - restoredCipherText.getBase64EncodedRawCipherText()); + ciphertext.getBase64EncodedRawCipherText(), + restoredCipherText.getBase64EncodedRawCipherText()); } catch(IOException ex) { ex.printStackTrace(System.err); @@ -313,29 +313,29 @@ public final void testMIC() { ex.printStackTrace(System.err); fail("testJavaSerialization(): Unexpected ClassNotFoundException: " + ex); } catch (EncryptionException ex) { - ex.printStackTrace(System.err); - fail("testJavaSerialization(): Unexpected EncryptionException: " + ex); - } catch (IllegalBlockSizeException ex) { - ex.printStackTrace(System.err); - fail("testJavaSerialization(): Unexpected IllegalBlockSizeException: " + ex); - } catch (BadPaddingException ex) { - ex.printStackTrace(System.err); - fail("testJavaSerialization(): Unexpected BadPaddingException: " + ex); - } catch (InvalidKeyException ex) { - ex.printStackTrace(System.err); - fail("testJavaSerialization(): Unexpected InvalidKeyException: " + ex); - } catch (InvalidAlgorithmParameterException ex) { - ex.printStackTrace(System.err); - fail("testJavaSerialization(): Unexpected InvalidAlgorithmParameterException: " + ex); - } - } - - /** - * Run all the test cases in this suite. - * This is to allow running from {@code org.owasp.esapi.AllTests} which - * uses a JUnit 3 test runner. - */ - public static junit.framework.Test suite() { - return new JUnit4TestAdapter(CipherTextTest.class); - } + ex.printStackTrace(System.err); + fail("testJavaSerialization(): Unexpected EncryptionException: " + ex); + } catch (IllegalBlockSizeException ex) { + ex.printStackTrace(System.err); + fail("testJavaSerialization(): Unexpected IllegalBlockSizeException: " + ex); + } catch (BadPaddingException ex) { + ex.printStackTrace(System.err); + fail("testJavaSerialization(): Unexpected BadPaddingException: " + ex); + } catch (InvalidKeyException ex) { + ex.printStackTrace(System.err); + fail("testJavaSerialization(): Unexpected InvalidKeyException: " + ex); + } catch (InvalidAlgorithmParameterException ex) { + ex.printStackTrace(System.err); + fail("testJavaSerialization(): Unexpected InvalidAlgorithmParameterException: " + ex); + } + } + + /** + * Run all the test cases in this suite. + * This is to allow running from {@code org.owasp.esapi.AllTests} which + * uses a JUnit 3 test runner. + */ + public static junit.framework.Test suite() { + return new JUnit4TestAdapter(CipherTextTest.class); + } } diff --git a/src/test/java/org/owasp/esapi/crypto/CryptoHelperTest.java b/src/test/java/org/owasp/esapi/crypto/CryptoHelperTest.java index aa7ae0cf3..8a327ed76 100644 --- a/src/test/java/org/owasp/esapi/crypto/CryptoHelperTest.java +++ b/src/test/java/org/owasp/esapi/crypto/CryptoHelperTest.java @@ -148,26 +148,26 @@ public final void testArrayCompare() { @Test public final void testIsValidKDFVersion() { - assertTrue( CryptoHelper.isValidKDFVersion(20110203, false, false)); - assertTrue( CryptoHelper.isValidKDFVersion(20130830, false, false)); - assertTrue( CryptoHelper.isValidKDFVersion(33330303, false, false)); - assertTrue( CryptoHelper.isValidKDFVersion(99991231, false, false)); - - assertFalse( CryptoHelper.isValidKDFVersion(0, false, false)); - assertFalse( CryptoHelper.isValidKDFVersion(99991232, false, false)); - assertFalse( CryptoHelper.isValidKDFVersion(20110202, false, false)); - - assertTrue( CryptoHelper.isValidKDFVersion(20110203, true, false)); - assertTrue( CryptoHelper.isValidKDFVersion(KeyDerivationFunction.kdfVersion, true, false)); - assertFalse( CryptoHelper.isValidKDFVersion(KeyDerivationFunction.kdfVersion + 1, true, false)); - - try { - CryptoHelper.isValidKDFVersion(77777777, true, true); - fail("Failed to CryptoHelper.isValidKDFVersion() failed to throw IllegalArgumentException."); - } - catch (Exception e) { - assertTrue( e instanceof IllegalArgumentException); - } + assertTrue( CryptoHelper.isValidKDFVersion(20110203, false, false)); + assertTrue( CryptoHelper.isValidKDFVersion(20130830, false, false)); + assertTrue( CryptoHelper.isValidKDFVersion(33330303, false, false)); + assertTrue( CryptoHelper.isValidKDFVersion(99991231, false, false)); + + assertFalse( CryptoHelper.isValidKDFVersion(0, false, false)); + assertFalse( CryptoHelper.isValidKDFVersion(99991232, false, false)); + assertFalse( CryptoHelper.isValidKDFVersion(20110202, false, false)); + + assertTrue( CryptoHelper.isValidKDFVersion(20110203, true, false)); + assertTrue( CryptoHelper.isValidKDFVersion(KeyDerivationFunction.kdfVersion, true, false)); + assertFalse( CryptoHelper.isValidKDFVersion(KeyDerivationFunction.kdfVersion + 1, true, false)); + + try { + CryptoHelper.isValidKDFVersion(77777777, true, true); + fail("Failed to CryptoHelper.isValidKDFVersion() failed to throw IllegalArgumentException."); + } + catch (Exception e) { + assertTrue( e instanceof IllegalArgumentException); + } } private void fillByteArray(byte[] ba, byte b) { diff --git a/src/test/java/org/owasp/esapi/crypto/ESAPICryptoMACByPassTest.java b/src/test/java/org/owasp/esapi/crypto/ESAPICryptoMACByPassTest.java index eecc11caa..863c573e7 100644 --- a/src/test/java/org/owasp/esapi/crypto/ESAPICryptoMACByPassTest.java +++ b/src/test/java/org/owasp/esapi/crypto/ESAPICryptoMACByPassTest.java @@ -19,7 +19,7 @@ * Original class name: SignatureByPassTest. * * NOTE: If this test fails, your version of ESAPI is vulnerable (or you have - * it configured not to require a MAC which you should NOT do). + * it configured not to require a MAC which you should NOT do). */ package org.owasp.esapi.crypto; @@ -49,7 +49,7 @@ public class ESAPICryptoMACByPassTest { @Before public void setUp() throws NoSuchAlgorithmException, InvalidKeySpecException { - ; // Do any prerequisite setup here. + ; // Do any prerequisite setup here. } @Test @@ -61,21 +61,21 @@ public void testMacBypass() throws EncryptionException, NoSuchFieldException, Il //Encryption with MAC String originalMessage = "Cryptography!?!?"; System.out.printf("Encrypting the message '%s'\n", originalMessage); - // Until there is a better way to do this. But this is much easier - // than having to set up a custom ESAPI.properties file just for - // this test. - // - // NOTE: Philippe Arteau's original exploit used "AES/OFB/NoPadding" + // Until there is a better way to do this. But this is much easier + // than having to set up a custom ESAPI.properties file just for + // this test. + // + // NOTE: Philippe Arteau's original exploit used "AES/OFB/NoPadding" // so that one could see that the effect of the decryption would - // be "Craptography!?!?". However, if you wish to do that, then - // you must also change the ESAPI.properties file used by ESAPI - // JUnit tests sp that "OFB" is accepted as an allowed cipher - // mode. The easiest way to do that (if you are still not convinced) - // is to add "OFB" mode to Encryptor.cipher_modes.additional_allowed; - // e.g., Encryptor.cipher_modes.additional_allowed=CBC,OFB - // + // be "Craptography!?!?". However, if you wish to do that, then + // you must also change the ESAPI.properties file used by ESAPI + // JUnit tests sp that "OFB" is accepted as an allowed cipher + // mode. The easiest way to do that (if you are still not convinced) + // is to add "OFB" mode to Encryptor.cipher_modes.additional_allowed; + // e.g., Encryptor.cipher_modes.additional_allowed=CBC,OFB + // String origCipherXform = - ESAPI.securityConfiguration().setCipherTransformation("AES/CBC/NoPadding"); + ESAPI.securityConfiguration().setCipherTransformation("AES/CBC/NoPadding"); CipherText ct = ESAPI.encryptor().encrypt(sk,new PlainText(originalMessage)); //Serialize the ciphertext in order to send it over the wire.. @@ -87,20 +87,20 @@ public void testMacBypass() throws EncryptionException, NoSuchFieldException, Il //Decrypt CipherText modifierCtObj = CipherText.fromPortableSerializedBytes(modifiedCt); try { - ESAPI.securityConfiguration().setCipherTransformation(origCipherXform); - // This decryption should fail by throwing an EncryptionException - // if ESAPI crypto is NOT vulnerable and you never get to the - // subsequent lines in the try block. + ESAPI.securityConfiguration().setCipherTransformation(origCipherXform); + // This decryption should fail by throwing an EncryptionException + // if ESAPI crypto is NOT vulnerable and you never get to the + // subsequent lines in the try block. PlainText pt = ESAPI.encryptor().decrypt(sk,modifierCtObj); System.out.printf("Decrypting to '%s' (probably will look like garbage!)\n", new String(pt.asBytes())); System.out.println("This ESAPI version vulnerable to MAC by-pass described in GitHub issue # 312! Upgrade to latest version."); fail("This ESAPI version is vulnerable to MAC by-pass described in GitHub issue # 312! Upgrade to latest version."); } catch(EncryptionException eex) { - String errMsg = eex.getMessage(); - // See private String DECRYPTION_FAILED in JavaEncryptor. - String expectedError = "Decryption failed; see logs for details."; - assertTrue( errMsg.equals(expectedError) ); - System.out.println("testMacByPass(): Attempted decryption after MAC tampering failed."); + String errMsg = eex.getMessage(); + // See private String DECRYPTION_FAILED in JavaEncryptor. + String expectedError = "Decryption failed; see logs for details."; + assertTrue( errMsg.equals(expectedError) ); + System.out.println("testMacByPass(): Attempted decryption after MAC tampering failed."); System.out.println("Fix of issue # 306 successful. Crypto MAC by-pass test failed; exception was: [" + eex + "]"); } } diff --git a/src/test/java/org/owasp/esapi/crypto/PlainTextTest.java b/src/test/java/org/owasp/esapi/crypto/PlainTextTest.java index 135b6d8c5..4e40c3225 100644 --- a/src/test/java/org/owasp/esapi/crypto/PlainTextTest.java +++ b/src/test/java/org/owasp/esapi/crypto/PlainTextTest.java @@ -10,59 +10,59 @@ import org.owasp.esapi.crypto.PlainText; public class PlainTextTest { - - private String unicodeStr = "A\u00ea\u00f1\u00fcC"; // I.e., "AêñüC" - private String altString = "AêñüC"; // Same as above. - - /* NOTE: This test will not work on Windows unless executed under - * Eclipse and the file is stored / treated as a UTF-8 encoded file - * rather than the Windows native OS encoding of Windows-1252 (aka, - * CP-1252). Therefore this test case has a check to not run the test - * unless - * unicodeStr.equals(altString) - * is true. If not the test is skipped and a message is printed to stderr. - * Jim Manico made an attempt to address this (see private email to - * kevin.w.wall@gmail.com on 11/26/2009, subject "Re: [OWASP-ESAPI] Unit - * Tests Status") to correct this problem by setting some SVN attribute - * to standardize all source files to UTF-8, but not all Subversion clients - * are either honoring this or perhaps Windows just overrides this. Either - * way, this test (which used to be an assertTrue() expression) was - * introduced to account for this. - */ - @Test - public final void testUnicodeString() { - // These 2 strings are *meant* to be equal. If they are not, please - // do *NOT* change the test. It's a Windows thing. Sorry. Change your - // OS instead. ;-) - if ( ! unicodeStr.equals(altString) ) { - System.err.println("Skipping JUnit test case " + - "PlainTextTest.testUnicodeString() on OS " + - System.getProperty("os.name") ); - return; - } - try { - byte[] utf8Bytes = unicodeStr.getBytes("UTF-8"); - PlainText pt1 = new PlainText(unicodeStr); - PlainText pt2 = new PlainText(altString); - - assertTrue( pt1.equals(pt1) ); // Equals self - assertFalse( pt1.equals(null) ); - assertTrue( pt1.equals(pt2) ); - assertFalse( pt1.equals( unicodeStr ) ); - assertTrue( pt1.length() == utf8Bytes.length ); - assertTrue( Arrays.equals(utf8Bytes, pt1.asBytes()) ); - assertTrue( pt1.hashCode() == unicodeStr.hashCode() ); - - } catch (UnsupportedEncodingException e) { - fail("No UTF-8 byte encoding: " + e); - e.printStackTrace(System.err); - } - } - - @Test - public final void testNullCase() { - int counter = 0; - try { + + private String unicodeStr = "A\u00ea\u00f1\u00fcC"; // I.e., "AêñüC" + private String altString = "AêñüC"; // Same as above. + + /* NOTE: This test will not work on Windows unless executed under + * Eclipse and the file is stored / treated as a UTF-8 encoded file + * rather than the Windows native OS encoding of Windows-1252 (aka, + * CP-1252). Therefore this test case has a check to not run the test + * unless + * unicodeStr.equals(altString) + * is true. If not the test is skipped and a message is printed to stderr. + * Jim Manico made an attempt to address this (see private email to + * kevin.w.wall@gmail.com on 11/26/2009, subject "Re: [OWASP-ESAPI] Unit + * Tests Status") to correct this problem by setting some SVN attribute + * to standardize all source files to UTF-8, but not all Subversion clients + * are either honoring this or perhaps Windows just overrides this. Either + * way, this test (which used to be an assertTrue() expression) was + * introduced to account for this. + */ + @Test + public final void testUnicodeString() { + // These 2 strings are *meant* to be equal. If they are not, please + // do *NOT* change the test. It's a Windows thing. Sorry. Change your + // OS instead. ;-) + if ( ! unicodeStr.equals(altString) ) { + System.err.println("Skipping JUnit test case " + + "PlainTextTest.testUnicodeString() on OS " + + System.getProperty("os.name") ); + return; + } + try { + byte[] utf8Bytes = unicodeStr.getBytes("UTF-8"); + PlainText pt1 = new PlainText(unicodeStr); + PlainText pt2 = new PlainText(altString); + + assertTrue( pt1.equals(pt1) ); // Equals self + assertFalse( pt1.equals(null) ); + assertTrue( pt1.equals(pt2) ); + assertFalse( pt1.equals( unicodeStr ) ); + assertTrue( pt1.length() == utf8Bytes.length ); + assertTrue( Arrays.equals(utf8Bytes, pt1.asBytes()) ); + assertTrue( pt1.hashCode() == unicodeStr.hashCode() ); + + } catch (UnsupportedEncodingException e) { + fail("No UTF-8 byte encoding: " + e); + e.printStackTrace(System.err); + } + } + + @Test + public final void testNullCase() { + int counter = 0; + try { byte[] bytes = null; PlainText pt = new PlainText(bytes); fail("testNullCase(): Expected IllegalArgumentException"); @@ -71,54 +71,54 @@ public final void testNullCase() { } catch (Exception e) { fail("testNullCase(): Caught unexpected exception: " + e); } - } + } - @Test - public final void testEmptyString() { - PlainText mt = new PlainText(""); - assertTrue( mt.length() == 0 ); - byte[] ba = mt.asBytes(); - assertTrue( ba != null && ba.length == 0 ); - } + @Test + public final void testEmptyString() { + PlainText mt = new PlainText(""); + assertTrue( mt.length() == 0 ); + byte[] ba = mt.asBytes(); + assertTrue( ba != null && ba.length == 0 ); + } - @Test - public final void testOverwrite() { - try { - byte[] origBytes = unicodeStr.getBytes("UTF-8"); - PlainText pt = new PlainText(origBytes); - assertTrue( pt.toString().equals(unicodeStr) ); - assertTrue( Arrays.equals(origBytes, pt.asBytes()) ); - assertTrue( pt.hashCode() == unicodeStr.hashCode() ); - - int origLen = origBytes.length; + @Test + public final void testOverwrite() { + try { + byte[] origBytes = unicodeStr.getBytes("UTF-8"); + PlainText pt = new PlainText(origBytes); + assertTrue( pt.toString().equals(unicodeStr) ); + assertTrue( Arrays.equals(origBytes, pt.asBytes()) ); + assertTrue( pt.hashCode() == unicodeStr.hashCode() ); + + int origLen = origBytes.length; - pt.overwrite(); - byte[] overwrittenBytes = pt.asBytes(); - assertTrue( overwrittenBytes != null ); - assertFalse( Arrays.equals( origBytes, overwrittenBytes ) ); + pt.overwrite(); + byte[] overwrittenBytes = pt.asBytes(); + assertTrue( overwrittenBytes != null ); + assertFalse( Arrays.equals( origBytes, overwrittenBytes ) ); - // Ensure that ALL the bytes overwritten with '*'. - int afterLen = overwrittenBytes.length; - assertTrue( origLen == afterLen ); - int sum = 0; - for( int i = 0; i < afterLen; i++ ) { - if ( overwrittenBytes[i] == '*' ) { - sum++; - } - } - assertTrue( afterLen == sum ); - } catch (UnsupportedEncodingException e) { - fail("No UTF-8 byte encoding: " + e); - e.printStackTrace(System.err); - } - } + // Ensure that ALL the bytes overwritten with '*'. + int afterLen = overwrittenBytes.length; + assertTrue( origLen == afterLen ); + int sum = 0; + for( int i = 0; i < afterLen; i++ ) { + if ( overwrittenBytes[i] == '*' ) { + sum++; + } + } + assertTrue( afterLen == sum ); + } catch (UnsupportedEncodingException e) { + fail("No UTF-8 byte encoding: " + e); + e.printStackTrace(System.err); + } + } - /** - * Run all the test cases in this suite. - * This is to allow running from {@code org.owasp.esapi.AllTests} which - * uses a JUnit 3 test runner. - */ - public static junit.framework.Test suite() { - return new JUnit4TestAdapter(PlainTextTest.class); - } + /** + * Run all the test cases in this suite. + * This is to allow running from {@code org.owasp.esapi.AllTests} which + * uses a JUnit 3 test runner. + */ + public static junit.framework.Test suite() { + return new JUnit4TestAdapter(PlainTextTest.class); + } } diff --git a/src/test/java/org/owasp/esapi/errors/EnterpriseSecurityExceptionTest.java b/src/test/java/org/owasp/esapi/errors/EnterpriseSecurityExceptionTest.java index bfd96514d..e42780251 100644 --- a/src/test/java/org/owasp/esapi/errors/EnterpriseSecurityExceptionTest.java +++ b/src/test/java/org/owasp/esapi/errors/EnterpriseSecurityExceptionTest.java @@ -45,11 +45,11 @@ public class EnterpriseSecurityExceptionTest extends TestCase { /** - * Instantiates a new access reference map test. - * - * @param testName - * the test name - */ + * Instantiates a new access reference map test. + * + * @param testName + * the test name + */ public EnterpriseSecurityExceptionTest(String testName) { super(testName); } @@ -59,7 +59,7 @@ public EnterpriseSecurityExceptionTest(String testName) { * @throws Exception */ protected void setUp() throws Exception { - // none + // none } /** @@ -67,14 +67,14 @@ protected void setUp() throws Exception { * @throws Exception */ protected void tearDown() throws Exception { - // none + // none } /** - * Suite. - * - * @return the test - */ + * Suite. + * + * @return the test + */ public static Test suite() { TestSuite suite = new TestSuite(EnterpriseSecurityExceptionTest.class); return suite; @@ -82,9 +82,9 @@ public static Test suite() { /** - * Test of update method, of class org.owasp.esapi.AccessReferenceMap. - * - */ + * Test of update method, of class org.owasp.esapi.AccessReferenceMap. + * + */ public void testExceptions() { System.out.println("exceptions"); EnterpriseSecurityException e = null; diff --git a/src/test/java/org/owasp/esapi/filters/ClickjackFilterTest.java b/src/test/java/org/owasp/esapi/filters/ClickjackFilterTest.java index 272dafbd8..d88031c8d 100644 --- a/src/test/java/org/owasp/esapi/filters/ClickjackFilterTest.java +++ b/src/test/java/org/owasp/esapi/filters/ClickjackFilterTest.java @@ -38,9 +38,9 @@ public class ClickjackFilterTest extends TestCase { /** - * @param testName - * the test name - */ + * @param testName + * the test name + */ public ClickjackFilterTest(String testName) { super(testName); } @@ -50,7 +50,7 @@ public ClickjackFilterTest(String testName) { * @throws Exception */ protected void setUp() throws Exception { - // none + // none } /** @@ -58,14 +58,14 @@ protected void setUp() throws Exception { * @throws Exception */ protected void tearDown() throws Exception { - // none + // none } /** - * Suite. - * - * @return the test - */ + * Suite. + * + * @return the test + */ public static Test suite() { TestSuite suite = new TestSuite(ClickjackFilterTest.class); return suite; @@ -73,30 +73,30 @@ public static Test suite() { /** - * Test of update method, of class org.owasp.esapi.AccessReferenceMap. + * Test of update method, of class org.owasp.esapi.AccessReferenceMap. * @throws Exception */ public void testFilter() throws Exception { System.out.println("ClickjackFilter"); Map map = new HashMap(); - FilterConfig mfc = new MockFilterConfig( map ); - ClickjackFilter filter = new ClickjackFilter(); - filter.init( mfc ); - MockHttpServletRequest request = new MockHttpServletRequest(); - - // the mock filter chain writes the requested URI to the response body - MockFilterChain chain = new MockFilterChain(); + FilterConfig mfc = new MockFilterConfig( map ); + ClickjackFilter filter = new ClickjackFilter(); + filter.init( mfc ); + MockHttpServletRequest request = new MockHttpServletRequest(); + + // the mock filter chain writes the requested URI to the response body + MockFilterChain chain = new MockFilterChain(); URL url = new URL( "http://www.example.com/index.jsp" ); - System.out.println( "\nTest request: " + url ); + System.out.println( "\nTest request: " + url ); request = new MockHttpServletRequest( url ); - MockHttpServletResponse response = new MockHttpServletResponse(); - try { - filter.doFilter(request, response, chain); + MockHttpServletResponse response = new MockHttpServletResponse(); + try { + filter.doFilter(request, response, chain); } catch( Exception e ) { - e.printStackTrace(); - fail(); + e.printStackTrace(); + fail(); } String header = response.getHeader( "X-FRAME-OPTIONS"); System.out.println(">>>" + header ); diff --git a/src/test/java/org/owasp/esapi/filters/SafeRequestTest.java b/src/test/java/org/owasp/esapi/filters/SafeRequestTest.java index db2f0d770..24db938c7 100644 --- a/src/test/java/org/owasp/esapi/filters/SafeRequestTest.java +++ b/src/test/java/org/owasp/esapi/filters/SafeRequestTest.java @@ -29,112 +29,112 @@ */ public class SafeRequestTest extends TestCase { - /** - * Instantiates a new access controller test. - * - * @param testName - * the test name - * @throws Exception - */ - public SafeRequestTest(String testName) throws Exception { - super(testName); - } - - /** - * {@inheritDoc} - * - * @throws Exception - */ - protected void setUp() throws Exception { - } - - /** - * {@inheritDoc} - * - * @throws Exception - */ - protected void tearDown() throws Exception { - // none - } - - /** - * Suite. - * - * @return the test - */ - public static Test suite() { - TestSuite suite = new TestSuite(SafeRequestTest.class); - return suite; - } - - /** - * - */ - public void testGetRequestParameters() { - System.out.println( "getRequestParameters"); - MockHttpServletRequest request = new MockHttpServletRequest(); - request.addParameter( "one","1" ); - request.addParameter( "two","2" ); - request.addParameter( "one","3" ); - request.addParameter( "one","4" ); - SecurityWrapperRequest safeRequest = new SecurityWrapperRequest( request ); - String[] params = safeRequest.getParameterValues("one"); - String out = ""; - for (int i = 0; i < params.length; i++ ) out += params[i]; - assertEquals( "134", out ); - } - - public void testGetQueryStringNull() - { - MockHttpServletRequest req = new MockHttpServletRequest(); - SecurityWrapperRequest wrappedReq; - - req.setQueryString(null); - wrappedReq = new SecurityWrapperRequest(req); - assertNull(wrappedReq.getQueryString()); - } - - // Test to ensure null-value contract defined by ServletRequest.getParameterNames(String) is met. - public void testGetParameterValuesReturnsNullWhenParameterDoesNotExistInRequest() { - MockHttpServletRequest request = new MockHttpServletRequest(); - request.clearParameters(); + /** + * Instantiates a new access controller test. + * + * @param testName + * the test name + * @throws Exception + */ + public SafeRequestTest(String testName) throws Exception { + super(testName); + } + + /** + * {@inheritDoc} + * + * @throws Exception + */ + protected void setUp() throws Exception { + } + + /** + * {@inheritDoc} + * + * @throws Exception + */ + protected void tearDown() throws Exception { + // none + } + + /** + * Suite. + * + * @return the test + */ + public static Test suite() { + TestSuite suite = new TestSuite(SafeRequestTest.class); + return suite; + } + + /** + * + */ + public void testGetRequestParameters() { + System.out.println( "getRequestParameters"); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter( "one","1" ); + request.addParameter( "two","2" ); + request.addParameter( "one","3" ); + request.addParameter( "one","4" ); + SecurityWrapperRequest safeRequest = new SecurityWrapperRequest( request ); + String[] params = safeRequest.getParameterValues("one"); + String out = ""; + for (int i = 0; i < params.length; i++ ) out += params[i]; + assertEquals( "134", out ); + } + + public void testGetQueryStringNull() + { + MockHttpServletRequest req = new MockHttpServletRequest(); + SecurityWrapperRequest wrappedReq; + + req.setQueryString(null); + wrappedReq = new SecurityWrapperRequest(req); + assertNull(wrappedReq.getQueryString()); + } + + // Test to ensure null-value contract defined by ServletRequest.getParameterNames(String) is met. + public void testGetParameterValuesReturnsNullWhenParameterDoesNotExistInRequest() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.clearParameters(); - final String paramName = "nonExistentParameter"; - assertNull(request.getParameterValues(paramName)); - - SecurityWrapperRequest safeRequest = new SecurityWrapperRequest(request); - assertNull("Expecting null value to be returned for non-existent parameter.", safeRequest.getParameterValues(paramName)); - } - - public void testGetParameterValuesReturnsCorrectValueWhenParameterExistsInRequest() { - MockHttpServletRequest request = new MockHttpServletRequest(); - request.clearParameters(); - - final String paramName = "existentParameter"; - final String paramValue = "foobar"; - request.addParameter(paramName, paramValue); - assertTrue(request.getParameterValues(paramName)[0].equals(paramValue)); - - SecurityWrapperRequest safeRequest = new SecurityWrapperRequest(request); - final String actualParamValue = safeRequest.getParameterValues(paramName)[0]; - assertEquals(paramValue, actualParamValue); - } - - public void testGetParameterValuesReturnsCorrectValuesWhenParameterExistsMultipleTimesInRequest() { - MockHttpServletRequest request = new MockHttpServletRequest(); - request.clearParameters(); - - final String paramName = "existentParameter"; - final String paramValue_0 = "foobar"; - final String paramValue_1 = "barfoo"; - request.addParameter(paramName, paramValue_0); - request.addParameter(paramName, paramValue_1); - assertTrue(request.getParameterValues(paramName)[0].equals(paramValue_0)); - assertTrue(request.getParameterValues(paramName)[1].equals(paramValue_1)); - - SecurityWrapperRequest safeRequest = new SecurityWrapperRequest(request); - final String[] actualParamValues = safeRequest.getParameterValues(paramName); - assertEquals(paramValue_0, actualParamValues[0]); - assertEquals(paramValue_1, actualParamValues[1]); - } + final String paramName = "nonExistentParameter"; + assertNull(request.getParameterValues(paramName)); + + SecurityWrapperRequest safeRequest = new SecurityWrapperRequest(request); + assertNull("Expecting null value to be returned for non-existent parameter.", safeRequest.getParameterValues(paramName)); + } + + public void testGetParameterValuesReturnsCorrectValueWhenParameterExistsInRequest() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.clearParameters(); + + final String paramName = "existentParameter"; + final String paramValue = "foobar"; + request.addParameter(paramName, paramValue); + assertTrue(request.getParameterValues(paramName)[0].equals(paramValue)); + + SecurityWrapperRequest safeRequest = new SecurityWrapperRequest(request); + final String actualParamValue = safeRequest.getParameterValues(paramName)[0]; + assertEquals(paramValue, actualParamValue); + } + + public void testGetParameterValuesReturnsCorrectValuesWhenParameterExistsMultipleTimesInRequest() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.clearParameters(); + + final String paramName = "existentParameter"; + final String paramValue_0 = "foobar"; + final String paramValue_1 = "barfoo"; + request.addParameter(paramName, paramValue_0); + request.addParameter(paramName, paramValue_1); + assertTrue(request.getParameterValues(paramName)[0].equals(paramValue_0)); + assertTrue(request.getParameterValues(paramName)[1].equals(paramValue_1)); + + SecurityWrapperRequest safeRequest = new SecurityWrapperRequest(request); + final String[] actualParamValues = safeRequest.getParameterValues(paramName); + assertEquals(paramValue_0, actualParamValues[0]); + assertEquals(paramValue_1, actualParamValues[1]); + } } diff --git a/src/test/java/org/owasp/esapi/filters/SecurityWrapperRequestTest.java b/src/test/java/org/owasp/esapi/filters/SecurityWrapperRequestTest.java index 03b776df8..d7faddb8a 100644 --- a/src/test/java/org/owasp/esapi/filters/SecurityWrapperRequestTest.java +++ b/src/test/java/org/owasp/esapi/filters/SecurityWrapperRequestTest.java @@ -61,8 +61,8 @@ @PrepareForTest(ESAPI.class) public class SecurityWrapperRequestTest { protected static final String ESAPI_VALIDATOR_GETTER_METHOD_NAME = "validator"; - protected static final String ESAPI_GET_LOGGER_METHOD_NAME = "getLogger"; - protected static final String ESAPY_SECURITY_CONFIGURATION_GETTER_METHOD_NAME = "securityConfiguration"; + protected static final String ESAPI_GET_LOGGER_METHOD_NAME = "getLogger"; + protected static final String ESAPY_SECURITY_CONFIGURATION_GETTER_METHOD_NAME = "securityConfiguration"; protected static final String SECURITY_CONFIGURATION_QUERY_STRING_LENGTH_KEY_NAME = "HttpUtilities.URILENGTH"; protected static final String SECURITY_CONFIGURATION_PARAMETER_STRING_LENGTH_KEY_NAME = "HttpUtilities.httpQueryParamValueLength"; private static final String SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME = "HttpUtilities.MaxHeaderNameSize"; @@ -384,81 +384,81 @@ public void testGetParameterStringBooleanIntStringNullOnException() throws Excep @Test public void testGetCookie() throws Exception { - PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn( - SECURITY_CONFIGURATION_TEST_LENGTH); - PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn( - SECURITY_CONFIGURATION_TEST_LENGTH); - - Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE"); - ck1.setMaxAge(999); - ck1.setDomain(testName.getMethodName() + "-DOMAIN"); - ck1.setPath(testName.getMethodName() + "-URI"); - - Cookie[] stubCookies = new Cookie[] {ck1}; - PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies); - - PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getName()); - PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getValue()),eq(COOKIE_VALUE_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenReturn(ck1.getValue()); - PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getDomain()),eq(COOKIE_DOMAIN_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getDomain()); - PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getPath()), eq(COOKIE_PATH_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getPath()); - - SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest); - Cookie[] cookies = request.getCookies(); - assertNotEquals(stubCookies, cookies); - assertEquals(1, cookies.length); - Cookie resultCookie = cookies[0]; - assertNotEquals(ck1, resultCookie); - assertEquals(ck1.getName(), resultCookie.getName()); - assertEquals(ck1.getValue(), resultCookie.getValue()); - assertEquals(ck1.getDomain(), resultCookie.getDomain()); - assertEquals(ck1.getPath(), resultCookie.getPath()); - assertEquals(ck1.getMaxAge(), resultCookie.getMaxAge()); - - Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); - Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true)); - Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); - Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); + PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn( + SECURITY_CONFIGURATION_TEST_LENGTH); + PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn( + SECURITY_CONFIGURATION_TEST_LENGTH); + + Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE"); + ck1.setMaxAge(999); + ck1.setDomain(testName.getMethodName() + "-DOMAIN"); + ck1.setPath(testName.getMethodName() + "-URI"); + + Cookie[] stubCookies = new Cookie[] {ck1}; + PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies); + + PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getName()); + PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getValue()),eq(COOKIE_VALUE_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenReturn(ck1.getValue()); + PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getDomain()),eq(COOKIE_DOMAIN_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getDomain()); + PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getPath()), eq(COOKIE_PATH_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getPath()); + + SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest); + Cookie[] cookies = request.getCookies(); + assertNotEquals(stubCookies, cookies); + assertEquals(1, cookies.length); + Cookie resultCookie = cookies[0]; + assertNotEquals(ck1, resultCookie); + assertEquals(ck1.getName(), resultCookie.getName()); + assertEquals(ck1.getValue(), resultCookie.getValue()); + assertEquals(ck1.getDomain(), resultCookie.getDomain()); + assertEquals(ck1.getPath(), resultCookie.getPath()); + assertEquals(ck1.getMaxAge(), resultCookie.getMaxAge()); + + Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); + Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true)); + Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); + Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); } @Test public void testGetCookieNullDomainPath() throws Exception { - PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn( - SECURITY_CONFIGURATION_TEST_LENGTH); - PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn( - SECURITY_CONFIGURATION_TEST_LENGTH); - - Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE"); - ck1.setMaxAge(999); - //Domain and Path are left null - - Cookie[] stubCookies = new Cookie[] {ck1}; - PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies); - - PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getName()); - PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getValue()),eq(COOKIE_VALUE_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenReturn(ck1.getValue()); - - SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest); - Cookie[] cookies = request.getCookies(); - assertNotEquals(stubCookies, cookies); - assertEquals(1, cookies.length); - Cookie resultCookie1 = cookies[0]; - - assertNotEquals(ck1, resultCookie1); - assertEquals(ck1.getName(), resultCookie1.getName()); - assertEquals(ck1.getValue(), resultCookie1.getValue()); - assertEquals(ck1.getDomain(), resultCookie1.getDomain()); - assertEquals(ck1.getPath(), resultCookie1.getPath()); - assertEquals(ck1.getMaxAge(), resultCookie1.getMaxAge()); - - Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); - Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true)); - Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); - Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); + PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn( + SECURITY_CONFIGURATION_TEST_LENGTH); + PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn( + SECURITY_CONFIGURATION_TEST_LENGTH); + + Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE"); + ck1.setMaxAge(999); + //Domain and Path are left null + + Cookie[] stubCookies = new Cookie[] {ck1}; + PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies); + + PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getName()); + PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getValue()),eq(COOKIE_VALUE_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenReturn(ck1.getValue()); + + SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest); + Cookie[] cookies = request.getCookies(); + assertNotEquals(stubCookies, cookies); + assertEquals(1, cookies.length); + Cookie resultCookie1 = cookies[0]; + + assertNotEquals(ck1, resultCookie1); + assertEquals(ck1.getName(), resultCookie1.getName()); + assertEquals(ck1.getValue(), resultCookie1.getValue()); + assertEquals(ck1.getDomain(), resultCookie1.getDomain()); + assertEquals(ck1.getPath(), resultCookie1.getPath()); + assertEquals(ck1.getMaxAge(), resultCookie1.getMaxAge()); + + Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); + Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true)); + Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); + Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); } @Test public void testGetCookieNullRequestCookies() { - PowerMockito.when(mockRequest.getParameter(testParameterName)).thenReturn(testParameterValue); + PowerMockito.when(mockRequest.getParameter(testParameterName)).thenReturn(testParameterValue); PowerMockito.when(mockRequest.getCookies()).thenReturn(null); SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest); Cookie[] cookies = request.getCookies(); @@ -467,137 +467,137 @@ public void testGetCookieNullRequestCookies() { @Test public void testGetCookieSkipOnBadName() throws Exception { - PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn( - SECURITY_CONFIGURATION_TEST_LENGTH); - PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn( - SECURITY_CONFIGURATION_TEST_LENGTH); + PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn( + SECURITY_CONFIGURATION_TEST_LENGTH); + PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn( + SECURITY_CONFIGURATION_TEST_LENGTH); - Answer exceptionAnswer = new ValidatorTestContainer(mockValidator).throwException(); + Answer exceptionAnswer = new ValidatorTestContainer(mockValidator).throwException(); - Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE"); - ck1.setMaxAge(999); - ck1.setDomain(testName.getMethodName() + "-DOMAIN"); - ck1.setPath(testName.getMethodName() + "-URI"); - - Cookie[] stubCookies = new Cookie[] {ck1}; - PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies); - - PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenAnswer(exceptionAnswer); - - SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest); - Cookie[] cookies = request.getCookies(); - assertNotEquals(stubCookies, cookies); - assertEquals(0, cookies.length); - - Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); - Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true)); - Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); - Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); - - //I would have liked to verify the logging occurred, but it's giving me trouble at this time. + Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE"); + ck1.setMaxAge(999); + ck1.setDomain(testName.getMethodName() + "-DOMAIN"); + ck1.setPath(testName.getMethodName() + "-URI"); + + Cookie[] stubCookies = new Cookie[] {ck1}; + PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies); + + PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenAnswer(exceptionAnswer); + + SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest); + Cookie[] cookies = request.getCookies(); + assertNotEquals(stubCookies, cookies); + assertEquals(0, cookies.length); + + Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); + Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true)); + Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); + Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); + + //I would have liked to verify the logging occurred, but it's giving me trouble at this time. } @Test public void testGetCookieSkipOnBadValue() throws Exception { - PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn( - SECURITY_CONFIGURATION_TEST_LENGTH); - PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn( - SECURITY_CONFIGURATION_TEST_LENGTH); - - Answer exceptionAnswer = new ValidatorTestContainer(mockValidator).throwException(); - - Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE"); - ck1.setMaxAge(999); - ck1.setDomain(testName.getMethodName() + "-DOMAIN"); - ck1.setPath(testName.getMethodName() + "-URI"); - - Cookie[] stubCookies = new Cookie[] {ck1}; - PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies); - - PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenReturn(ck1.getName()); - PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getValue()),eq(COOKIE_VALUE_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenAnswer(exceptionAnswer); - - SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest); - Cookie[] cookies = request.getCookies(); - assertNotEquals(stubCookies, cookies); - assertEquals(0, cookies.length); - - Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); - Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true)); - Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); - Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); - - //I would have liked to verify the logging occurred, but it's giving me trouble at this time. + PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn( + SECURITY_CONFIGURATION_TEST_LENGTH); + PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn( + SECURITY_CONFIGURATION_TEST_LENGTH); + + Answer exceptionAnswer = new ValidatorTestContainer(mockValidator).throwException(); + + Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE"); + ck1.setMaxAge(999); + ck1.setDomain(testName.getMethodName() + "-DOMAIN"); + ck1.setPath(testName.getMethodName() + "-URI"); + + Cookie[] stubCookies = new Cookie[] {ck1}; + PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies); + + PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenReturn(ck1.getName()); + PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getValue()),eq(COOKIE_VALUE_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenAnswer(exceptionAnswer); + + SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest); + Cookie[] cookies = request.getCookies(); + assertNotEquals(stubCookies, cookies); + assertEquals(0, cookies.length); + + Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); + Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true)); + Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); + Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); + + //I would have liked to verify the logging occurred, but it's giving me trouble at this time. } @Test public void testGetCookieSkipOnBadDomain() throws Exception { - PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn( - SECURITY_CONFIGURATION_TEST_LENGTH); - PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn( - SECURITY_CONFIGURATION_TEST_LENGTH); + PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn( + SECURITY_CONFIGURATION_TEST_LENGTH); + PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn( + SECURITY_CONFIGURATION_TEST_LENGTH); - Answer exceptionAnswer = new ValidatorTestContainer(mockValidator).throwException(); + Answer exceptionAnswer = new ValidatorTestContainer(mockValidator).throwException(); - Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE"); - ck1.setMaxAge(999); - ck1.setDomain(testName.getMethodName() + "-DOMAIN"); - ck1.setPath(testName.getMethodName() + "-URI"); - - Cookie[] stubCookies = new Cookie[] {ck1}; - PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies); - - PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getName()); + Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE"); + ck1.setMaxAge(999); + ck1.setDomain(testName.getMethodName() + "-DOMAIN"); + ck1.setPath(testName.getMethodName() + "-URI"); + + Cookie[] stubCookies = new Cookie[] {ck1}; + PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies); + + PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getName()); PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getValue()),eq(COOKIE_VALUE_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenReturn(ck1.getValue()); - PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getDomain()),eq(COOKIE_DOMAIN_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenAnswer(exceptionAnswer); - - SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest); - Cookie[] cookies = request.getCookies(); - assertNotEquals(stubCookies, cookies); - assertEquals(0, cookies.length); - - Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); - Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true)); - Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); - Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); - - //I would have liked to verify the logging occurred, but it's giving me trouble at this time. + PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getDomain()),eq(COOKIE_DOMAIN_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenAnswer(exceptionAnswer); + + SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest); + Cookie[] cookies = request.getCookies(); + assertNotEquals(stubCookies, cookies); + assertEquals(0, cookies.length); + + Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); + Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true)); + Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); + Mockito.verify(mockValidator, times(0)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); + + //I would have liked to verify the logging occurred, but it's giving me trouble at this time. } @Test public void testGetCookieSkipOnBadPath() throws Exception { - PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn( - SECURITY_CONFIGURATION_TEST_LENGTH); - PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn( - SECURITY_CONFIGURATION_TEST_LENGTH); + PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_NAME_LENGTH_KEY_NAME)).thenReturn( + SECURITY_CONFIGURATION_TEST_LENGTH); + PowerMockito.when(mockSecConfig.getIntProp(SECURITY_CONFIGURATION_HEADER_VALUE_LENGTH_KEY_NAME)).thenReturn( + SECURITY_CONFIGURATION_TEST_LENGTH); - Answer exceptionAnswer = new ValidatorTestContainer(mockValidator).throwException(); + Answer exceptionAnswer = new ValidatorTestContainer(mockValidator).throwException(); - Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE"); - ck1.setMaxAge(999); - ck1.setDomain(testName.getMethodName() + "-DOMAIN"); - ck1.setPath(testName.getMethodName() + "-URI"); - - Cookie[] stubCookies = new Cookie[] {ck1}; - PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies); - - PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getName()); - PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getValue()),eq(COOKIE_VALUE_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenReturn(ck1.getValue()); - PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getDomain()),eq(COOKIE_DOMAIN_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getDomain()); - PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getPath()), eq(COOKIE_PATH_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenAnswer(exceptionAnswer); - - SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest); - Cookie[] cookies = request.getCookies(); - assertNotEquals(stubCookies, cookies); - assertEquals(0, cookies.length); - - Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); - Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true)); - Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); - Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); - - //I would have liked to verify the logging occurred, but it's giving me trouble at this time. + Cookie ck1 = new Cookie(testName.getMethodName(), testName.getMethodName()+ "-VALUE"); + ck1.setMaxAge(999); + ck1.setDomain(testName.getMethodName() + "-DOMAIN"); + ck1.setPath(testName.getMethodName() + "-URI"); + + Cookie[] stubCookies = new Cookie[] {ck1}; + PowerMockito.when(mockRequest.getCookies()).thenReturn(stubCookies); + + PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getName()), eq(COOKIE_NAME_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getName()); + PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getValue()),eq(COOKIE_VALUE_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(true))).thenReturn(ck1.getValue()); + PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getDomain()),eq(COOKIE_DOMAIN_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenReturn(ck1.getDomain()); + PowerMockito.when(mockValidator.getValidInput(anyString(), eq(ck1.getPath()), eq(COOKIE_PATH_TYPE_KEY), eq(SECURITY_CONFIGURATION_TEST_LENGTH), eq(false))).thenAnswer(exceptionAnswer); + + SecurityWrapperRequest request = new SecurityWrapperRequest(mockRequest); + Cookie[] cookies = request.getCookies(); + assertNotEquals(stubCookies, cookies); + assertEquals(0, cookies.length); + + Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getName()), ArgumentMatchers.eq(COOKIE_NAME_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); + Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getValue()), ArgumentMatchers.eq(COOKIE_VALUE_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(true)); + Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getDomain()), ArgumentMatchers.eq(COOKIE_DOMAIN_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); + Mockito.verify(mockValidator, times(1)).getValidInput(anyString(), ArgumentMatchers.eq(ck1.getPath()), ArgumentMatchers.eq(COOKIE_PATH_TYPE_KEY), ArgumentMatchers.eq(SECURITY_CONFIGURATION_TEST_LENGTH), ArgumentMatchers.eq(false)); + + //I would have liked to verify the logging occurred, but it's giving me trouble at this time. } /** diff --git a/src/test/java/org/owasp/esapi/http/MockFilterChain.java b/src/test/java/org/owasp/esapi/http/MockFilterChain.java index 06951efa5..d9427a471 100644 --- a/src/test/java/org/owasp/esapi/http/MockFilterChain.java +++ b/src/test/java/org/owasp/esapi/http/MockFilterChain.java @@ -38,9 +38,9 @@ public class MockFilterChain implements FilterChain { * @throws javax.servlet.ServletException */ public void doFilter( ServletRequest request, ServletResponse response ) throws IOException, ServletException { - System.out.println( "CHAIN received " + request.getClass().getName() + " and is issuing " + response.getClass().getName() ); - response.getOutputStream().println( " This is the body of a response for " + ((HttpServletRequest)request).getRequestURI() ); - ((HttpServletResponse)response).addCookie( new Cookie( "name", "value" ) ); + System.out.println( "CHAIN received " + request.getClass().getName() + " and is issuing " + response.getClass().getName() ); + response.getOutputStream().println( " This is the body of a response for " + ((HttpServletRequest)request).getRequestURI() ); + ((HttpServletResponse)response).addCookie( new Cookie( "name", "value" ) ); } } diff --git a/src/test/java/org/owasp/esapi/http/MockFilterConfig.java b/src/test/java/org/owasp/esapi/http/MockFilterConfig.java index b7715a478..77ef982f2 100644 --- a/src/test/java/org/owasp/esapi/http/MockFilterConfig.java +++ b/src/test/java/org/owasp/esapi/http/MockFilterConfig.java @@ -27,14 +27,14 @@ * to pass information to a filter during initialization. */ public class MockFilterConfig implements FilterConfig { - private Map map; + private Map map; - public MockFilterConfig( Map map ) { - this.map = map; - } - + public MockFilterConfig( Map map ) { + this.map = map; + } + public String getFilterName() { - return "mock"; + return "mock"; } /** @@ -42,7 +42,7 @@ public String getFilterName() { * is executing. */ public ServletContext getServletContext() { - return new MockServletContext(); + return new MockServletContext(); } /** @@ -51,7 +51,7 @@ public ServletContext getServletContext() { * the parameter does not exist. */ public String getInitParameter(String name) { - return (String)map.get( name ); + return (String)map.get( name ); } /** @@ -61,6 +61,6 @@ public String getInitParameter(String name) { * no initialization parameters. */ public Enumeration getInitParameterNames() { - return Collections.enumeration( map.keySet() ); + return Collections.enumeration( map.keySet() ); } } diff --git a/src/test/java/org/owasp/esapi/http/MockHttpServletRequest.java b/src/test/java/org/owasp/esapi/http/MockHttpServletRequest.java index d085b7cb3..a7128e661 100644 --- a/src/test/java/org/owasp/esapi/http/MockHttpServletRequest.java +++ b/src/test/java/org/owasp/esapi/http/MockHttpServletRequest.java @@ -56,627 +56,627 @@ */ public class MockHttpServletRequest implements HttpServletRequest { - private static final String HDR_CONTENT_TYPE = "Content-Type"; - private static final String[] EMPTY_STRING_ARRAY = new String[0]; - - /** The requestDispatcher */ - private RequestDispatcher requestDispatcher = new MockRequestDispatcher(); - - /** The session. */ - private MockHttpSession session = null; - - /** The cookies. */ - private ArrayList cookies = new ArrayList(); - - /** The parameters. */ - private Map parameters = new HashMap(); - - /** The headers. */ - private Map> headers = new HashMap>(); - - private byte[] body; - - private String scheme = "https"; - - private String remoteHost = "64.14.103.52"; - - private String serverHost = "64.14.103.52"; - - private String uri = "/test"; - - private String queryString = "pid=1&qid=test"; - - private String method = "POST"; - - private Map attrs = new HashMap(); - - public MockHttpServletRequest() { - } - - public MockHttpServletRequest(String uri, byte[] body) { - this.body = body; - this.uri = uri; - } - - public MockHttpServletRequest( URL url ) { - scheme = url.getProtocol(); - serverHost = url.getHost(); - uri = url.getPath(); - } - - public String getAuthType() { - return null; - } - - public String getContextPath() { - return null; - } - - /** - * Adds the parameter. - * - * @param name the name - * @param value the value - */ - public void addParameter(String name, String value) { - String[] old = parameters.get(name); - if ( old == null ) { - old = new String[0]; - } - String[] updated = new String[old.length + 1]; - for ( int i = 0; i < old.length; i++ ) updated[i] = old[i]; - updated[old.length] = value; - parameters.put(name, updated); - } - - /** - * removeParameter removes the parameter name from the parameters map if it exists - * - * @param name - * parameter name to be removed - */ - public void removeParameter( String name ) { - parameters.remove( name ); - } - - /** - * Adds the header. - * - * @param name the name - * @param value the value - */ - public void addHeader(String name, String value) - { - List values; - - if((values = headers.get(name))==null) - { - values = new ArrayList(); - headers.put(name, values); - } - values.add(value); - } - - /** - * Set a header replacing any previous value(s). - * @param name the header name - * @param value the header value - */ - public void setHeader(String name, String value) - { - List values = new ArrayList(); - - values.add(value); - headers.put(name,values); - } - - /** - * Sets the cookies. - * - * @param list the new cookies - */ - public void setCookies(ArrayList list) { - cookies = list; - } - - public void setCookie(String name, String value ) { - Cookie c = new Cookie( name, value ); - cookies.add( c ); - } - - public boolean clearCookie(String name) { - return cookies.remove(name); - } - - public void clearCookies() { - cookies.clear(); - } - - /** - * {@inheritDoc} - */ - public Cookie[] getCookies() { - if ( cookies.isEmpty() ) return null; - return cookies.toArray(new Cookie[0]); - } - - /** - * {@inheritDoc} - */ - public long getDateHeader(String name) { - try { - Date date = SimpleDateFormat.getDateTimeInstance().parse( getParameter( name ) ); - return date.getTime(); // TODO needs to be HTTP format - } catch( ParseException e ) { - return 0; - } - } - - /** - * {@inheritDoc} - * @param name - * @return The requested header value. - */ - public String getHeader(String name) { - List values; - - if((values = headers.get(name))==null) - return null; - if(values.size() == 0) - return null; - return values.get(0); - } - - /** - * {@inheritDoc} - * @return Enumeration of header names as strings - */ - public Enumeration getHeaderNames() - { - return Collections.enumeration(headers.keySet()); - } - - /** - * {@inheritDoc} - */ - public Enumeration getHeaders(String name) { - Vector v = new Vector(); - v.add( getHeader( name ) ); - return v.elements(); - } - - /** - * {@inheritDoc} - */ - public int getIntHeader(String name) { - - return 0; - } - - /** - * {@inheritDoc} - */ - public String getMethod() { - return method; - } - - public void setMethod( String value ) { - method = value; - } - - /** - * {@inheritDoc} - */ - public String getPathInfo() { - - return null; - } - - /** - * {@inheritDoc} - */ - public String getPathTranslated() { - - return null; - } - - /** - * {@inheritDoc} - */ - public String getQueryString() { - return queryString; - } - - /** - * Set the query string to return. - * @param str The query string to return. - */ - public void setQueryString(String str) - { - this.queryString = str; - } - - /** - * {@inheritDoc} - */ - public String getRemoteUser() { - - return null; - } - - /** - * {@inheritDoc} - */ - public String getRequestURI() { - return uri; - } - - /** - * {@inheritDoc} - */ - public StringBuffer getRequestURL() { - return new StringBuffer( getScheme() + "://" + this.getServerName() + getRequestURI() + "?" + getQueryString() ); - } - - /** - * {@inheritDoc} - */ - public String getRequestedSessionId() { - - return null; - } - - /** - * {@inheritDoc} - */ - public String getServletPath() { - - return null; - } - - /** - * {@inheritDoc} - */ - public HttpSession getSession() { - if (session != null) { - return getSession(false); - } - return getSession(true); - } - - /** - * {@inheritDoc} - */ - public HttpSession getSession(boolean create) { - if (session == null && create) { - session = new MockHttpSession(); - } else if (session != null && session.getInvalidated()) { - session = new MockHttpSession(); - } - return session; - } - - /** - * {@inheritDoc} - */ - public Principal getUserPrincipal() { - - return null; - } - - /** - * {@inheritDoc} - */ - public boolean isRequestedSessionIdFromCookie() { - - return false; - } - - /** - * {@inheritDoc} - */ - public boolean isRequestedSessionIdFromURL() { - - return false; - } - - /** - * {@inheritDoc} - * @deprecated - */ - @Deprecated - public boolean isRequestedSessionIdFromUrl() { - - return false; - } - - /** - * {@inheritDoc} - */ - public boolean isRequestedSessionIdValid() { - - return false; - } - - /** - * {@inheritDoc} - */ - public boolean isUserInRole(String role) { - - return false; - } - - /** - * {@inheritDoc} - */ - public Object getAttribute(String name) { - return attrs.get(name); - } - - /** - * {@inheritDoc} - */ - public Enumeration getAttributeNames() { - return Collections.enumeration(attrs.keySet()); - } - - /** - * {@inheritDoc} - */ - public String getCharacterEncoding() { - - return null; - } - - /** - * {@inheritDoc} - */ - public int getContentLength() { - return body.length; - } - - /** - * {@inheritDoc} - */ - public String getContentType() { - return getHeader(HDR_CONTENT_TYPE); - } - - public void setContentType( String value ) { - setHeader(HDR_CONTENT_TYPE, value); - } - - /** - * {@inheritDoc} - */ - public ServletInputStream getInputStream() throws IOException { - return new MockServletInputStream(body); - } - - /** - * {@inheritDoc} - */ - public String getLocalAddr() { - return "10.1.43.6"; - } - - /** - * {@inheritDoc} - */ - public String getLocalName() { - return "www.domain.com"; - } - - /** - * {@inheritDoc} - */ - public int getLocalPort() { - return 80; - } - - /** - * {@inheritDoc} - */ - public Locale getLocale() { - return null; - } - - /** - * {@inheritDoc} - */ - public Enumeration getLocales() { - return null; - } - - /** - * {@inheritDoc} - */ - public String getParameter(String name) { - String[] values = parameters.get(name); - if ( values == null ) return null; - return values[0]; - } - - public void clearParameter(String name) { - parameters.remove( name ); - } - - public void clearParameters() { - parameters.clear(); - } - - /** - * {@inheritDoc} - */ - public Map getParameterMap() { - return parameters; - } - - /** - * {@inheritDoc} - */ - public Enumeration getParameterNames() { - return Collections.enumeration(parameters.keySet()); - } - - /** - * {@inheritDoc} - */ - public String[] getParameterValues(String name) { - return parameters.get(name); - } - - /** - * {@inheritDoc} - */ - public String getProtocol() { - return "HTTP/1.1"; - } - - /** - * {@inheritDoc} - */ - public BufferedReader getReader() throws IOException { - - return null; - } - - /** - * {@inheritDoc} - * @deprecated - */ - @Deprecated - public String getRealPath(String path) { - - return null; - } - - /** - * {@inheritDoc} - */ - public String getRemoteAddr() { - return remoteHost; - } - - public void setRemoteAddr(String remoteHost) { - this.remoteHost = remoteHost; - } - - /** - * {@inheritDoc} - */ - public String getRemoteHost() { - return remoteHost; - } - - /** - * {@inheritDoc} - */ - public int getRemotePort() { - - return 0; - } - - /** - * {@inheritDoc} - */ - public RequestDispatcher getRequestDispatcher(String path) { - return requestDispatcher; - } - - /** - * {@inheritDoc} - */ - public String getScheme() { - return scheme; - } - - /** - * {@inheritDoc} - */ - public String getServerName() { - return serverHost; - } - - /** - * {@inheritDoc} - */ - public int getServerPort() { - return 80; - } - - /** - * {@inheritDoc} - */ - public boolean isSecure() { - return scheme.equals( "https" ); - } - - /** - * {@inheritDoc} - */ - public void removeAttribute(String name) { - attrs.remove(name); - } - - /** - * {@inheritDoc} - */ - public void setAttribute(String name, Object o) { - attrs.put(name,o); - } - - /** - * {@inheritDoc} - */ - public void setCharacterEncoding(String env) throws UnsupportedEncodingException { - - } - - public void setRequestURI(String uri) throws UnsupportedEncodingException { - this.uri = uri; - } - - public void setRequestURL(String url) throws UnsupportedEncodingException { - // get the scheme - int p = url.indexOf( ":" ); - this.scheme = url.substring( 0, p ); - - // get the queryString - int q = url.indexOf( "?" ); - if ( q != -1 ) - { - queryString = url.substring( q+1 ); - url = url.substring( 0, q ); - } - else - queryString = null; - } - - public void setScheme( String scheme ) { - this.scheme = scheme; - } - - public void dump() - { - String[] names; - - System.out.println(); - System.out.println( " " + this.getMethod() + " " + this.getRequestURL() ); - - names = headers.keySet().toArray(EMPTY_STRING_ARRAY); - Arrays.sort(names); // make debugging a bit easier... - for (String name : names) - for(String value : headers.get(name)) - System.out.println( " " + name + ": " + value); - names = parameters.keySet().toArray(EMPTY_STRING_ARRAY); - Arrays.sort(names); - for (String name : names) { - for(String value : parameters.get(name)) - System.out.println( " " + name + "=" + value); - } - System.out.println( "\n" ); - } + private static final String HDR_CONTENT_TYPE = "Content-Type"; + private static final String[] EMPTY_STRING_ARRAY = new String[0]; + + /** The requestDispatcher */ + private RequestDispatcher requestDispatcher = new MockRequestDispatcher(); + + /** The session. */ + private MockHttpSession session = null; + + /** The cookies. */ + private ArrayList cookies = new ArrayList(); + + /** The parameters. */ + private Map parameters = new HashMap(); + + /** The headers. */ + private Map> headers = new HashMap>(); + + private byte[] body; + + private String scheme = "https"; + + private String remoteHost = "64.14.103.52"; + + private String serverHost = "64.14.103.52"; + + private String uri = "/test"; + + private String queryString = "pid=1&qid=test"; + + private String method = "POST"; + + private Map attrs = new HashMap(); + + public MockHttpServletRequest() { + } + + public MockHttpServletRequest(String uri, byte[] body) { + this.body = body; + this.uri = uri; + } + + public MockHttpServletRequest( URL url ) { + scheme = url.getProtocol(); + serverHost = url.getHost(); + uri = url.getPath(); + } + + public String getAuthType() { + return null; + } + + public String getContextPath() { + return null; + } + + /** + * Adds the parameter. + * + * @param name the name + * @param value the value + */ + public void addParameter(String name, String value) { + String[] old = parameters.get(name); + if ( old == null ) { + old = new String[0]; + } + String[] updated = new String[old.length + 1]; + for ( int i = 0; i < old.length; i++ ) updated[i] = old[i]; + updated[old.length] = value; + parameters.put(name, updated); + } + + /** + * removeParameter removes the parameter name from the parameters map if it exists + * + * @param name + * parameter name to be removed + */ + public void removeParameter( String name ) { + parameters.remove( name ); + } + + /** + * Adds the header. + * + * @param name the name + * @param value the value + */ + public void addHeader(String name, String value) + { + List values; + + if((values = headers.get(name))==null) + { + values = new ArrayList(); + headers.put(name, values); + } + values.add(value); + } + + /** + * Set a header replacing any previous value(s). + * @param name the header name + * @param value the header value + */ + public void setHeader(String name, String value) + { + List values = new ArrayList(); + + values.add(value); + headers.put(name,values); + } + + /** + * Sets the cookies. + * + * @param list the new cookies + */ + public void setCookies(ArrayList list) { + cookies = list; + } + + public void setCookie(String name, String value ) { + Cookie c = new Cookie( name, value ); + cookies.add( c ); + } + + public boolean clearCookie(String name) { + return cookies.remove(name); + } + + public void clearCookies() { + cookies.clear(); + } + + /** + * {@inheritDoc} + */ + public Cookie[] getCookies() { + if ( cookies.isEmpty() ) return null; + return cookies.toArray(new Cookie[0]); + } + + /** + * {@inheritDoc} + */ + public long getDateHeader(String name) { + try { + Date date = SimpleDateFormat.getDateTimeInstance().parse( getParameter( name ) ); + return date.getTime(); // TODO needs to be HTTP format + } catch( ParseException e ) { + return 0; + } + } + + /** + * {@inheritDoc} + * @param name + * @return The requested header value. + */ + public String getHeader(String name) { + List values; + + if((values = headers.get(name))==null) + return null; + if(values.size() == 0) + return null; + return values.get(0); + } + + /** + * {@inheritDoc} + * @return Enumeration of header names as strings + */ + public Enumeration getHeaderNames() + { + return Collections.enumeration(headers.keySet()); + } + + /** + * {@inheritDoc} + */ + public Enumeration getHeaders(String name) { + Vector v = new Vector(); + v.add( getHeader( name ) ); + return v.elements(); + } + + /** + * {@inheritDoc} + */ + public int getIntHeader(String name) { + + return 0; + } + + /** + * {@inheritDoc} + */ + public String getMethod() { + return method; + } + + public void setMethod( String value ) { + method = value; + } + + /** + * {@inheritDoc} + */ + public String getPathInfo() { + + return null; + } + + /** + * {@inheritDoc} + */ + public String getPathTranslated() { + + return null; + } + + /** + * {@inheritDoc} + */ + public String getQueryString() { + return queryString; + } + + /** + * Set the query string to return. + * @param str The query string to return. + */ + public void setQueryString(String str) + { + this.queryString = str; + } + + /** + * {@inheritDoc} + */ + public String getRemoteUser() { + + return null; + } + + /** + * {@inheritDoc} + */ + public String getRequestURI() { + return uri; + } + + /** + * {@inheritDoc} + */ + public StringBuffer getRequestURL() { + return new StringBuffer( getScheme() + "://" + this.getServerName() + getRequestURI() + "?" + getQueryString() ); + } + + /** + * {@inheritDoc} + */ + public String getRequestedSessionId() { + + return null; + } + + /** + * {@inheritDoc} + */ + public String getServletPath() { + + return null; + } + + /** + * {@inheritDoc} + */ + public HttpSession getSession() { + if (session != null) { + return getSession(false); + } + return getSession(true); + } + + /** + * {@inheritDoc} + */ + public HttpSession getSession(boolean create) { + if (session == null && create) { + session = new MockHttpSession(); + } else if (session != null && session.getInvalidated()) { + session = new MockHttpSession(); + } + return session; + } + + /** + * {@inheritDoc} + */ + public Principal getUserPrincipal() { + + return null; + } + + /** + * {@inheritDoc} + */ + public boolean isRequestedSessionIdFromCookie() { + + return false; + } + + /** + * {@inheritDoc} + */ + public boolean isRequestedSessionIdFromURL() { + + return false; + } + + /** + * {@inheritDoc} + * @deprecated + */ + @Deprecated + public boolean isRequestedSessionIdFromUrl() { + + return false; + } + + /** + * {@inheritDoc} + */ + public boolean isRequestedSessionIdValid() { + + return false; + } + + /** + * {@inheritDoc} + */ + public boolean isUserInRole(String role) { + + return false; + } + + /** + * {@inheritDoc} + */ + public Object getAttribute(String name) { + return attrs.get(name); + } + + /** + * {@inheritDoc} + */ + public Enumeration getAttributeNames() { + return Collections.enumeration(attrs.keySet()); + } + + /** + * {@inheritDoc} + */ + public String getCharacterEncoding() { + + return null; + } + + /** + * {@inheritDoc} + */ + public int getContentLength() { + return body.length; + } + + /** + * {@inheritDoc} + */ + public String getContentType() { + return getHeader(HDR_CONTENT_TYPE); + } + + public void setContentType( String value ) { + setHeader(HDR_CONTENT_TYPE, value); + } + + /** + * {@inheritDoc} + */ + public ServletInputStream getInputStream() throws IOException { + return new MockServletInputStream(body); + } + + /** + * {@inheritDoc} + */ + public String getLocalAddr() { + return "10.1.43.6"; + } + + /** + * {@inheritDoc} + */ + public String getLocalName() { + return "www.domain.com"; + } + + /** + * {@inheritDoc} + */ + public int getLocalPort() { + return 80; + } + + /** + * {@inheritDoc} + */ + public Locale getLocale() { + return null; + } + + /** + * {@inheritDoc} + */ + public Enumeration getLocales() { + return null; + } + + /** + * {@inheritDoc} + */ + public String getParameter(String name) { + String[] values = parameters.get(name); + if ( values == null ) return null; + return values[0]; + } + + public void clearParameter(String name) { + parameters.remove( name ); + } + + public void clearParameters() { + parameters.clear(); + } + + /** + * {@inheritDoc} + */ + public Map getParameterMap() { + return parameters; + } + + /** + * {@inheritDoc} + */ + public Enumeration getParameterNames() { + return Collections.enumeration(parameters.keySet()); + } + + /** + * {@inheritDoc} + */ + public String[] getParameterValues(String name) { + return parameters.get(name); + } + + /** + * {@inheritDoc} + */ + public String getProtocol() { + return "HTTP/1.1"; + } + + /** + * {@inheritDoc} + */ + public BufferedReader getReader() throws IOException { + + return null; + } + + /** + * {@inheritDoc} + * @deprecated + */ + @Deprecated + public String getRealPath(String path) { + + return null; + } + + /** + * {@inheritDoc} + */ + public String getRemoteAddr() { + return remoteHost; + } + + public void setRemoteAddr(String remoteHost) { + this.remoteHost = remoteHost; + } + + /** + * {@inheritDoc} + */ + public String getRemoteHost() { + return remoteHost; + } + + /** + * {@inheritDoc} + */ + public int getRemotePort() { + + return 0; + } + + /** + * {@inheritDoc} + */ + public RequestDispatcher getRequestDispatcher(String path) { + return requestDispatcher; + } + + /** + * {@inheritDoc} + */ + public String getScheme() { + return scheme; + } + + /** + * {@inheritDoc} + */ + public String getServerName() { + return serverHost; + } + + /** + * {@inheritDoc} + */ + public int getServerPort() { + return 80; + } + + /** + * {@inheritDoc} + */ + public boolean isSecure() { + return scheme.equals( "https" ); + } + + /** + * {@inheritDoc} + */ + public void removeAttribute(String name) { + attrs.remove(name); + } + + /** + * {@inheritDoc} + */ + public void setAttribute(String name, Object o) { + attrs.put(name,o); + } + + /** + * {@inheritDoc} + */ + public void setCharacterEncoding(String env) throws UnsupportedEncodingException { + + } + + public void setRequestURI(String uri) throws UnsupportedEncodingException { + this.uri = uri; + } + + public void setRequestURL(String url) throws UnsupportedEncodingException { + // get the scheme + int p = url.indexOf( ":" ); + this.scheme = url.substring( 0, p ); + + // get the queryString + int q = url.indexOf( "?" ); + if ( q != -1 ) + { + queryString = url.substring( q+1 ); + url = url.substring( 0, q ); + } + else + queryString = null; + } + + public void setScheme( String scheme ) { + this.scheme = scheme; + } + + public void dump() + { + String[] names; + + System.out.println(); + System.out.println( " " + this.getMethod() + " " + this.getRequestURL() ); + + names = headers.keySet().toArray(EMPTY_STRING_ARRAY); + Arrays.sort(names); // make debugging a bit easier... + for (String name : names) + for(String value : headers.get(name)) + System.out.println( " " + name + ": " + value); + names = parameters.keySet().toArray(EMPTY_STRING_ARRAY); + Arrays.sort(names); + for (String name : names) { + for(String value : parameters.get(name)) + System.out.println( " " + name + "=" + value); + } + System.out.println( "\n" ); + } @Override public boolean authenticate(HttpServletResponse hsr) throws IOException, ServletException { @@ -738,19 +738,19 @@ public DispatcherType getDispatcherType() { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - @Override - public long getContentLengthLong() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } + @Override + public long getContentLengthLong() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } - @Override - public String changeSessionId() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } + @Override + public String changeSessionId() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } - @Override - public T upgrade(Class handlerClass) throws IOException, ServletException { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } + @Override + public T upgrade(Class handlerClass) throws IOException, ServletException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } } diff --git a/src/test/java/org/owasp/esapi/http/MockHttpServletResponse.java b/src/test/java/org/owasp/esapi/http/MockHttpServletResponse.java index fa341db27..884c272ea 100644 --- a/src/test/java/org/owasp/esapi/http/MockHttpServletResponse.java +++ b/src/test/java/org/owasp/esapi/http/MockHttpServletResponse.java @@ -37,353 +37,353 @@ */ public class MockHttpServletResponse implements HttpServletResponse { - /** The cookies. */ - List cookies = new ArrayList(); - - /** The header names. */ - List headerNames = new ArrayList(); - - /** The header values. */ - List headerValues = new ArrayList(); - - /** The status. */ - int status = 200; - - StringBuffer body = new StringBuffer(); - - String contentType = "text/html; charset=ISO-8895-1"; - - public String getBody() { - return body.toString(); - } - - /** - * {@inheritDoc} - */ - public void addCookie(Cookie cookie) { - cookies.add(cookie); - } - - public List getCookies() { - return cookies; - } - - public Cookie getCookie(String name) { - Iterator i = cookies.iterator(); - while (i.hasNext()) { - Cookie c = i.next(); - if (c.getName().equals(name)) { - return c; - } - } - return null; - } - - /** - * {@inheritDoc} - */ - public void addDateHeader(String name, long date) { - headerNames.add(name); - headerValues.add("" + date); - } - - /** - * {@inheritDoc} - */ - public void addHeader(String name, String value) { - headerNames.add(name); - headerValues.add(value); - } - - /** - * {@inheritDoc} - */ - public void addIntHeader(String name, int value) { - headerNames.add(name); - headerValues.add("" + value); - } - - /** - * {@inheritDoc} - */ - public boolean containsHeader(String name) { - return headerNames.contains(name); - } - - /** - * {@inheritDoc} - */ - public String getHeader(String name) { - int index = headerNames.indexOf(name); - if (index != -1) { - return headerValues.get(index); - } - return null; - } - - /** - * Gets the header names. - * - * @return the header names - */ - public List getHeaderNames() { - return headerNames; - } - - /** - * {@inheritDoc} - */ - public String encodeRedirectURL(String url) { - return null; - } - - /** - * {@inheritDoc} - * @deprecated - */ - @Deprecated - public String encodeRedirectUrl(String url) { - return null; - } - - /** - * {@inheritDoc} - */ - public String encodeURL(String url) { - String enc = url; - try { enc = ESAPI.encoder().encodeForURL(url); - } catch( Exception e ) {} - return enc; - } - - /** - * {@inheritDoc} - * @deprecated - */ - @Deprecated - public String encodeUrl(String url) { - return encodeURL( url ); - } - - /** - * {@inheritDoc} - */ - public void sendError(int sc) throws IOException { - status = sc; - } - - /** - * {@inheritDoc} - */ - public void sendError(int sc, String msg) throws IOException { - status = sc; - } - - /** - * {@inheritDoc} - */ - public void sendRedirect(String location) throws IOException { - status = HttpServletResponse.SC_MOVED_PERMANENTLY; - body = new StringBuffer( "Redirect to " + location ); - } - - /** - * {@inheritDoc} - */ - public void setDateHeader(String name, long date) { - headerNames.add(name); - headerValues.add("" + date); - } - - /** - * {@inheritDoc} - */ - public void setHeader(String name, String value) { - headerNames.add(name); - headerValues.add(value); - } - - /** - * {@inheritDoc} - */ - public void setIntHeader(String name, int value) { - headerNames.add(name); - headerValues.add("" + value); - } - - /** - * {@inheritDoc} - */ - public void setStatus(int sc) { - status = sc; - } - - /** - * Gets the status. - * - * @return the status - */ - public int getStatus() { - return status; - } - - /** - * {@inheritDoc} - * @deprecated - */ - @Deprecated - public void setStatus(int sc, String sm) { - status = sc; - } - - /** - * {@inheritDoc} - */ - public void flushBuffer() throws IOException { - - } - - /** - * {@inheritDoc} - */ - public int getBufferSize() { - return body.length(); - } - - /** - * {@inheritDoc} - */ - public String getCharacterEncoding() { - return "UTF-8"; - } - - /** - * {@inheritDoc} - */ - public String getContentType() { - return contentType; - } - - /** - * {@inheritDoc} - */ - public Locale getLocale() { - - return null; - } - - /** - * {@inheritDoc} - */ - public ServletOutputStream getOutputStream() throws IOException { - return new ServletOutputStream() { - public void write(int b) throws IOException { - body.append((char)b); - } - - @Override - public boolean isReady() { - return false; - } - - @Override - public void setWriteListener(WriteListener writeListener) { - //NO-OP - } - }; - } - - /** - * {@inheritDoc} - */ - public PrintWriter getWriter() throws IOException { - return new PrintWriter( getOutputStream(), true ); - } - - /** - * {@inheritDoc} - */ - public boolean isCommitted() { - - return false; - } - - /** - * {@inheritDoc} - */ - public void reset() { - body = new StringBuffer(); - cookies = new ArrayList(); - headerNames = new ArrayList(); - headerValues = new ArrayList(); - status = 200; - } - - /** - * {@inheritDoc} - */ - public void resetBuffer() { - body = new StringBuffer(); - } - - public void setBody( String value ) { - body = new StringBuffer( value ); - } - - /** - * {@inheritDoc} - */ - public void setBufferSize(int size) { - - } - - /** - * {@inheritDoc} - */ - public void setCharacterEncoding(String charset) { - - } - - /** - * {@inheritDoc} - */ - public void setContentLength(int len) { - - } - - /** - * {@inheritDoc} - */ - public void setContentType(String type) { - contentType = type; - } - - /** - * {@inheritDoc} - */ - public void setLocale(Locale loc) { - - } - - /* - * Dump the response in a semi-readable format close to a real HTTP response on the wire - */ - public void dump() { + /** The cookies. */ + List cookies = new ArrayList(); + + /** The header names. */ + List headerNames = new ArrayList(); + + /** The header values. */ + List headerValues = new ArrayList(); + + /** The status. */ + int status = 200; + + StringBuffer body = new StringBuffer(); + + String contentType = "text/html; charset=ISO-8895-1"; + + public String getBody() { + return body.toString(); + } + + /** + * {@inheritDoc} + */ + public void addCookie(Cookie cookie) { + cookies.add(cookie); + } + + public List getCookies() { + return cookies; + } + + public Cookie getCookie(String name) { + Iterator i = cookies.iterator(); + while (i.hasNext()) { + Cookie c = i.next(); + if (c.getName().equals(name)) { + return c; + } + } + return null; + } + + /** + * {@inheritDoc} + */ + public void addDateHeader(String name, long date) { + headerNames.add(name); + headerValues.add("" + date); + } + + /** + * {@inheritDoc} + */ + public void addHeader(String name, String value) { + headerNames.add(name); + headerValues.add(value); + } + + /** + * {@inheritDoc} + */ + public void addIntHeader(String name, int value) { + headerNames.add(name); + headerValues.add("" + value); + } + + /** + * {@inheritDoc} + */ + public boolean containsHeader(String name) { + return headerNames.contains(name); + } + + /** + * {@inheritDoc} + */ + public String getHeader(String name) { + int index = headerNames.indexOf(name); + if (index != -1) { + return headerValues.get(index); + } + return null; + } + + /** + * Gets the header names. + * + * @return the header names + */ + public List getHeaderNames() { + return headerNames; + } + + /** + * {@inheritDoc} + */ + public String encodeRedirectURL(String url) { + return null; + } + + /** + * {@inheritDoc} + * @deprecated + */ + @Deprecated + public String encodeRedirectUrl(String url) { + return null; + } + + /** + * {@inheritDoc} + */ + public String encodeURL(String url) { + String enc = url; + try { enc = ESAPI.encoder().encodeForURL(url); + } catch( Exception e ) {} + return enc; + } + + /** + * {@inheritDoc} + * @deprecated + */ + @Deprecated + public String encodeUrl(String url) { + return encodeURL( url ); + } + + /** + * {@inheritDoc} + */ + public void sendError(int sc) throws IOException { + status = sc; + } + + /** + * {@inheritDoc} + */ + public void sendError(int sc, String msg) throws IOException { + status = sc; + } + + /** + * {@inheritDoc} + */ + public void sendRedirect(String location) throws IOException { + status = HttpServletResponse.SC_MOVED_PERMANENTLY; + body = new StringBuffer( "Redirect to " + location ); + } + + /** + * {@inheritDoc} + */ + public void setDateHeader(String name, long date) { + headerNames.add(name); + headerValues.add("" + date); + } + + /** + * {@inheritDoc} + */ + public void setHeader(String name, String value) { + headerNames.add(name); + headerValues.add(value); + } + + /** + * {@inheritDoc} + */ + public void setIntHeader(String name, int value) { + headerNames.add(name); + headerValues.add("" + value); + } + + /** + * {@inheritDoc} + */ + public void setStatus(int sc) { + status = sc; + } + + /** + * Gets the status. + * + * @return the status + */ + public int getStatus() { + return status; + } + + /** + * {@inheritDoc} + * @deprecated + */ + @Deprecated + public void setStatus(int sc, String sm) { + status = sc; + } + + /** + * {@inheritDoc} + */ + public void flushBuffer() throws IOException { + + } + + /** + * {@inheritDoc} + */ + public int getBufferSize() { + return body.length(); + } + + /** + * {@inheritDoc} + */ + public String getCharacterEncoding() { + return "UTF-8"; + } + + /** + * {@inheritDoc} + */ + public String getContentType() { + return contentType; + } + + /** + * {@inheritDoc} + */ + public Locale getLocale() { + + return null; + } + + /** + * {@inheritDoc} + */ + public ServletOutputStream getOutputStream() throws IOException { + return new ServletOutputStream() { + public void write(int b) throws IOException { + body.append((char)b); + } + + @Override + public boolean isReady() { + return false; + } + + @Override + public void setWriteListener(WriteListener writeListener) { + //NO-OP + } + }; + } + + /** + * {@inheritDoc} + */ + public PrintWriter getWriter() throws IOException { + return new PrintWriter( getOutputStream(), true ); + } + + /** + * {@inheritDoc} + */ + public boolean isCommitted() { + + return false; + } + + /** + * {@inheritDoc} + */ + public void reset() { + body = new StringBuffer(); + cookies = new ArrayList(); + headerNames = new ArrayList(); + headerValues = new ArrayList(); + status = 200; + } + + /** + * {@inheritDoc} + */ + public void resetBuffer() { + body = new StringBuffer(); + } + + public void setBody( String value ) { + body = new StringBuffer( value ); + } + + /** + * {@inheritDoc} + */ + public void setBufferSize(int size) { + + } + + /** + * {@inheritDoc} + */ + public void setCharacterEncoding(String charset) { + + } + + /** + * {@inheritDoc} + */ + public void setContentLength(int len) { + + } + + /** + * {@inheritDoc} + */ + public void setContentType(String type) { + contentType = type; + } + + /** + * {@inheritDoc} + */ + public void setLocale(Locale loc) { + + } + + /* + * Dump the response in a semi-readable format close to a real HTTP response on the wire + */ + public void dump() { System.out.println(); - System.out.println( " " + this.getStatus() + " " ); + System.out.println( " " + this.getStatus() + " " ); for ( Object name : getHeaderNames() ) System.out.println( " " + name + "=" + getHeader( (String)name ) ); System.out.println( " BODY: " + this.getBody() ); System.out.println(); - } + } @Override public Collection getHeaders(String string) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - @Override - public void setContentLengthLong(long len) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - + @Override + public void setContentLengthLong(long len) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + } diff --git a/src/test/java/org/owasp/esapi/http/MockHttpSession.java b/src/test/java/org/owasp/esapi/http/MockHttpSession.java index 6e9426a2b..ab3af4247 100644 --- a/src/test/java/org/owasp/esapi/http/MockHttpSession.java +++ b/src/test/java/org/owasp/esapi/http/MockHttpSession.java @@ -31,201 +31,201 @@ */ public class MockHttpSession implements HttpSession { - /** The invalidated. */ - boolean invalidated = false; - - /** The creation time. */ - private long creationTime=new Date().getTime(); - - /** The accessed time. */ - private long accessedTime=new Date().getTime(); - - /** The count. */ - private static int count = 1; - - /** The sessionid. */ - private int sessionid=count++; - - /** The attributes. */ - private Map attributes = new HashMap(); - - /** - * Instantiates a new test HTTP session. - */ - public MockHttpSession() { - // to replace synthetic accessor method - } - - /** - * Instantiates a new test http session. - * - * @param creationTime - * the creation time - * @param accessedTime - * the accessed time - */ - public MockHttpSession( long creationTime, long accessedTime ) { - this.creationTime = creationTime; - this.accessedTime = accessedTime; - } + /** The invalidated. */ + boolean invalidated = false; + + /** The creation time. */ + private long creationTime=new Date().getTime(); + + /** The accessed time. */ + private long accessedTime=new Date().getTime(); + + /** The count. */ + private static int count = 1; + + /** The sessionid. */ + private int sessionid=count++; + + /** The attributes. */ + private Map attributes = new HashMap(); + + /** + * Instantiates a new test HTTP session. + */ + public MockHttpSession() { + // to replace synthetic accessor method + } + + /** + * Instantiates a new test http session. + * + * @param creationTime + * the creation time + * @param accessedTime + * the accessed time + */ + public MockHttpSession( long creationTime, long accessedTime ) { + this.creationTime = creationTime; + this.accessedTime = accessedTime; + } /** * {@inheritDoc} */ - public Object getAttribute(String string) { - return attributes.get( string ); - } + public Object getAttribute(String string) { + return attributes.get( string ); + } /** * {@inheritDoc} */ - public Enumeration getAttributeNames() { - Vector v = new Vector( attributes.keySet() ); - return v.elements(); - } + public Enumeration getAttributeNames() { + Vector v = new Vector( attributes.keySet() ); + return v.elements(); + } /** * {@inheritDoc} */ - public long getCreationTime() { - return creationTime; - } + public long getCreationTime() { + return creationTime; + } /** * {@inheritDoc} */ - public String getId() { - return ""+sessionid; - } + public String getId() { + return ""+sessionid; + } - /** - * Gets the invalidated. - * - * @return the invalidated - */ - public boolean getInvalidated() { - return invalidated; - } + /** + * Gets the invalidated. + * + * @return the invalidated + */ + public boolean getInvalidated() { + return invalidated; + } /** * {@inheritDoc} */ - public long getLastAccessedTime() { - return accessedTime; - } + public long getLastAccessedTime() { + return accessedTime; + } /** * {@inheritDoc} */ - public int getMaxInactiveInterval() { - return 0; - } + public int getMaxInactiveInterval() { + return 0; + } /** * {@inheritDoc} */ - public ServletContext getServletContext() { - return null; - } + public ServletContext getServletContext() { + return null; + } /** * {@inheritDoc} * @deprecated */ @Deprecated - // need the full class here as for whatever stupid reason you can't - // seem to @SuppressWarnings{'deprecation'} on the import... *sigh* - public javax.servlet.http.HttpSessionContext getSessionContext() { - return null; - } + // need the full class here as for whatever stupid reason you can't + // seem to @SuppressWarnings{'deprecation'} on the import... *sigh* + public javax.servlet.http.HttpSessionContext getSessionContext() { + return null; + } /** * {@inheritDoc} * @deprecated */ - @Deprecated - public Object getValue(String string) { - return null; - } + @Deprecated + public Object getValue(String string) { + return null; + } /** * {@inheritDoc} * @deprecated */ - @Deprecated - public String[] getValueNames() { - return null; - } + @Deprecated + public String[] getValueNames() { + return null; + } /** * {@inheritDoc} - */ - public void invalidate() { - invalidated = true; - } + */ + public void invalidate() { + invalidated = true; + } /** * {@inheritDoc} */ - public boolean isNew() { - return true; - } + public boolean isNew() { + return true; + } - /** + /** * {@inheritDoc} * @deprecated */ - @Deprecated - public void putValue(String string, Object object) { - setAttribute( string, object ); - } + @Deprecated + public void putValue(String string, Object object) { + setAttribute( string, object ); + } /** * {@inheritDoc} */ - public void removeAttribute(String string) { - attributes.remove( string ); - } + public void removeAttribute(String string) { + attributes.remove( string ); + } /** * {@inheritDoc} * @deprecated */ - @Deprecated - public void removeValue(String string) { - removeAttribute( string ); - } + @Deprecated + public void removeValue(String string) { + removeAttribute( string ); + } /** * {@inheritDoc} */ - public void setAttribute(String string, Object object) { - attributes.put(string, object); - } + public void setAttribute(String string, Object object) { + attributes.put(string, object); + } /** * {@inheritDoc} = */ - public void setMaxInactiveInterval(int i) { - // stub - } - + public void setMaxInactiveInterval(int i) { + // stub + } + /** * * @param time */ public void setAccessedTime( long time ) { - this.accessedTime = time; - } + this.accessedTime = time; + } - + /** * * @param time */ public void setCreationTime( long time ) { - this.creationTime = time; - } + this.creationTime = time; + } } diff --git a/src/test/java/org/owasp/esapi/http/MockRequestDispatcher.java b/src/test/java/org/owasp/esapi/http/MockRequestDispatcher.java index 28f647157..66f53cc58 100644 --- a/src/test/java/org/owasp/esapi/http/MockRequestDispatcher.java +++ b/src/test/java/org/owasp/esapi/http/MockRequestDispatcher.java @@ -36,7 +36,7 @@ public class MockRequestDispatcher implements RequestDispatcher { * @throws java.io.IOException */ public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException { - System.out.println( "Forwarding" ); + System.out.println( "Forwarding" ); } /** @@ -47,7 +47,7 @@ public void forward(ServletRequest request, ServletResponse response) throws Ser * @throws java.io.IOException */ public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException { - System.out.println( "Including" ); + System.out.println( "Including" ); } } diff --git a/src/test/java/org/owasp/esapi/http/MockServletContext.java b/src/test/java/org/owasp/esapi/http/MockServletContext.java index cab828fc1..f230f77f2 100644 --- a/src/test/java/org/owasp/esapi/http/MockServletContext.java +++ b/src/test/java/org/owasp/esapi/http/MockServletContext.java @@ -93,7 +93,7 @@ public String getContextPath() { * @see RequestDispatcher */ public ServletContext getContext(String uripath) { - return null; + return null; } /** @@ -105,7 +105,7 @@ public ServletContext getContext(String uripath) { * @return 2 */ public int getMajorVersion() { - return 2; + return 2; } /** @@ -115,7 +115,7 @@ public int getMajorVersion() { * return the integer 4. */ public int getMinorVersion() { - return 4; + return 4; } /** @@ -131,7 +131,7 @@ public int getMinorVersion() { * @return a String specifying the file's MIME type */ public String getMimeType(String file) { - return "text/html"; + return "text/html"; } /** @@ -161,7 +161,7 @@ public String getMimeType(String file) { * @since Servlet 2.3 */ public Set getResourcePaths(String path) { - return null; + return null; } /** @@ -203,7 +203,7 @@ public Set getResourcePaths(String path) { * the correct form */ public URL getResource(String path) throws MalformedURLException { - return null; + return null; } /** @@ -238,7 +238,7 @@ public URL getResource(String path) throws MalformedURLException { * specified path */ public InputStream getResourceAsStream(String path) { - return null; + return null; } /** @@ -265,7 +265,7 @@ public InputStream getResourceAsStream(String path) { * @see ServletContext#getContext */ public RequestDispatcher getRequestDispatcher(String path) { - return null; + return null; } /** @@ -294,7 +294,7 @@ public RequestDispatcher getRequestDispatcher(String path) { * @see ServletConfig#getServletName */ public RequestDispatcher getNamedDispatcher(String name) { - return null; + return null; } /** @@ -312,7 +312,7 @@ public RequestDispatcher getNamedDispatcher(String name) { */ @Deprecated public Servlet getServlet(String name) throws ServletException { - return null; + return null; } /** @@ -327,7 +327,7 @@ public Servlet getServlet(String name) throws ServletException { */ @Deprecated public Enumeration getServlets() { - return null; + return null; } /** @@ -342,7 +342,7 @@ public Enumeration getServlets() { */ @Deprecated public Enumeration getServletNames() { - return null; + return null; } /** @@ -354,7 +354,7 @@ public Enumeration getServletNames() { * message to be written to the log file */ public void log(String msg) { - ESAPI.getLogger( "MockServletContext" ).warning( Logger.EVENT_FAILURE, msg ); + ESAPI.getLogger( "MockServletContext" ).warning( Logger.EVENT_FAILURE, msg ); } /** @@ -368,7 +368,7 @@ public void log(String msg) { */ @Deprecated public void log(Exception exception, String msg) { - ESAPI.getLogger( "MockServletContext" ).warning( Logger.EVENT_FAILURE, msg, exception ); + ESAPI.getLogger( "MockServletContext" ).warning( Logger.EVENT_FAILURE, msg, exception ); } /** @@ -384,7 +384,7 @@ public void log(Exception exception, String msg) { * or exception */ public void log(String message, Throwable throwable) { - ESAPI.getLogger( "MockServletContext" ).warning( Logger.EVENT_FAILURE, message, throwable ); + ESAPI.getLogger( "MockServletContext" ).warning( Logger.EVENT_FAILURE, message, throwable ); } /** @@ -408,7 +408,7 @@ public void log(String message, Throwable throwable) { * or null if the translation cannot be performed */ public String getRealPath(String path) { - return ESAPI.securityConfiguration().getResourceFile( path ).getAbsolutePath(); + return ESAPI.securityConfiguration().getResourceFile( path ).getAbsolutePath(); } /** @@ -428,7 +428,7 @@ public String getRealPath(String path) { * servlet container name and version number */ public String getServerInfo() { - return null; + return null; } /** @@ -450,7 +450,7 @@ public String getServerInfo() { * @see ServletConfig#getInitParameter */ public String getInitParameter(String name) { - return null; + return null; } /** @@ -465,7 +465,7 @@ public String getInitParameter(String name) { * @see ServletConfig#getInitParameter */ public Enumeration getInitParameterNames() { - return null; + return null; } @@ -496,7 +496,7 @@ public Enumeration getInitParameterNames() { * @see ServletContext#getAttributeNames */ public Object getAttribute(String name) { - return null; + return null; } /** @@ -511,7 +511,7 @@ public Object getAttribute(String name) { * @see #getAttribute */ public Enumeration getAttributeNames() { - return null; + return null; } /** @@ -561,7 +561,7 @@ public void removeAttribute(String name) { * @since Servlet 2.3 */ public String getServletContextName() { - return null; + return null; } @Override @@ -694,8 +694,8 @@ public void declareRoles(String... strings) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - @Override - public String getVirtualServerName() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } + @Override + public String getVirtualServerName() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } } \ No newline at end of file diff --git a/src/test/java/org/owasp/esapi/http/MockServletInputStream.java b/src/test/java/org/owasp/esapi/http/MockServletInputStream.java index 62ff01c0e..ea6e6fa14 100644 --- a/src/test/java/org/owasp/esapi/http/MockServletInputStream.java +++ b/src/test/java/org/owasp/esapi/http/MockServletInputStream.java @@ -47,23 +47,23 @@ public int read() throws IOException { if (next < body.length) { return body[next++]; } else { - isDone = true; + isDone = true; return -1; } } - @Override - public boolean isFinished() { - return isDone; - } + @Override + public boolean isFinished() { + return isDone; + } - @Override - public boolean isReady() { - return false; - } + @Override + public boolean isReady() { + return false; + } - @Override - public void setReadListener(ReadListener readListener) { - //NO_OP - } + @Override + public void setReadListener(ReadListener readListener) { + //NO_OP + } } diff --git a/src/test/java/org/owasp/esapi/logging/appender/ClientInfoSupplierTest.java b/src/test/java/org/owasp/esapi/logging/appender/ClientInfoSupplierTest.java index 61c0fba6e..53c622b0d 100644 --- a/src/test/java/org/owasp/esapi/logging/appender/ClientInfoSupplierTest.java +++ b/src/test/java/org/owasp/esapi/logging/appender/ClientInfoSupplierTest.java @@ -30,139 +30,139 @@ @PrepareForTest({ESAPI.class}) @PowerMockIgnore("javax.security.*") //Required since User extends javax.security.Principal public class ClientInfoSupplierTest { - private static final String ESAPI_SESSION_ATTR = "ESAPI_SESSION"; - - @Rule + private static final String ESAPI_SESSION_ATTR = "ESAPI_SESSION"; + + @Rule public TestName testName = new TestName(); - - private HttpServletRequest mockRequest; - private HttpSession mockSession; - private Authenticator mockAuth; - private Randomizer mockRand; - private User mockUser; - - @Before - public void before() throws Exception { - mockAuth =mock(Authenticator.class); - mockRand =mock(Randomizer.class); - mockRequest =mock(HttpServletRequest.class); - mockSession =mock(HttpSession.class); - mockUser =mock(User.class); - - mockStatic(ESAPI.class); - when(ESAPI.class, "currentRequest").thenReturn(mockRequest); - when(ESAPI.class, "authenticator").thenReturn(mockAuth); - when(ESAPI.class, "randomizer").thenReturn(mockRand); - - when(mockRequest.getSession(false)).thenReturn(mockSession); - when(mockSession.getAttribute(ESAPI_SESSION_ATTR)).thenReturn(testName.getMethodName()+ "-SESSION"); - - //Session value generation - when(mockRand.getRandomInteger(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt())).thenReturn(55555); - - when(mockUser.getLastHostAddress()).thenReturn(testName.getMethodName() + "-HOST_ADDR"); - - - when(mockAuth.getCurrentUser()).thenReturn(mockUser); - } - - @Test - public void testHappyPath() throws Exception { - ClientInfoSupplier cis = new ClientInfoSupplier(); - cis.setLogClientInfo(true); - String result = cis.get(); - - assertEquals(testName.getMethodName() + "-SESSION@"+testName.getMethodName() + "-HOST_ADDR", result); - - verify(mockAuth,times(1)).getCurrentUser(); - verify(mockRequest,times(1)).getSession(false); - verify(mockSession,times(1)).getAttribute(ESAPI_SESSION_ATTR); - verify(mockUser,times(1)).getLastHostAddress(); - - verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser); - } - - @Test - public void testLogUserOff() { - ClientInfoSupplier cis = new ClientInfoSupplier(); - cis.setLogClientInfo(false); - String result = cis.get(); - - assertTrue(result.isEmpty()); - - verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser); - } - - @Test - public void testLogUserNull() { - when(mockAuth.getCurrentUser()).thenReturn(null); - ClientInfoSupplier cis = new ClientInfoSupplier(); - cis.setLogClientInfo(true); - String result = cis.get(); - - assertEquals(testName.getMethodName()+ "-SESSION@#UNKNOWN_HOST#", result); - - verify(mockAuth,times(1)).getCurrentUser(); - verify(mockRequest,times(1)).getSession(false); - verify(mockSession,times(1)).getAttribute(ESAPI_SESSION_ATTR); - - verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser); - } - - @Test - public void testNullRequest() throws Exception { - when(ESAPI.class, "currentRequest").thenReturn(null); - ClientInfoSupplier cis = new ClientInfoSupplier(); - cis.setLogClientInfo(true); - String result = cis.get(); - - //sid is empty when request is null - assertEquals("@"+testName.getMethodName() + "-HOST_ADDR", result); - - verify(mockAuth,times(1)).getCurrentUser(); - verify(mockUser,times(1)).getLastHostAddress(); - - verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser); - } - - @Test - public void testNullSession() throws Exception { - when(mockRequest.getSession(false)).thenReturn(null); - ClientInfoSupplier cis = new ClientInfoSupplier(); - cis.setLogClientInfo(true); - String result = cis.get(); - - //sid is empty when session is null - assertEquals("@"+testName.getMethodName() + "-HOST_ADDR", result); - - - verify(mockAuth,times(1)).getCurrentUser(); - verify(mockRequest,times(1)).getSession(false); - verify(mockUser,times(1)).getLastHostAddress(); - - - verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser); - } - - - - @Test - public void testNullEsapiSession() throws Exception { - when(mockSession.getAttribute(ESAPI_SESSION_ATTR)).thenReturn(null); - ClientInfoSupplier cis = new ClientInfoSupplier(); - cis.setLogClientInfo(true); - String result = cis.get(); - - //sid is empty when session is null - assertEquals("55555@"+testName.getMethodName() + "-HOST_ADDR", result); - - verify(mockAuth,times(1)).getCurrentUser(); - verify(mockRequest,times(1)).getSession(false); - verify(mockSession,times(1)).getAttribute(ESAPI_SESSION_ATTR); - verify(mockSession, times(1)).setAttribute(ESAPI_SESSION_ATTR, (""+55555)); - verify(mockRand, times(1)).getRandomInteger(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt()); - verify(mockUser,times(1)).getLastHostAddress(); - - verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser); - } + + private HttpServletRequest mockRequest; + private HttpSession mockSession; + private Authenticator mockAuth; + private Randomizer mockRand; + private User mockUser; + + @Before + public void before() throws Exception { + mockAuth =mock(Authenticator.class); + mockRand =mock(Randomizer.class); + mockRequest =mock(HttpServletRequest.class); + mockSession =mock(HttpSession.class); + mockUser =mock(User.class); + + mockStatic(ESAPI.class); + when(ESAPI.class, "currentRequest").thenReturn(mockRequest); + when(ESAPI.class, "authenticator").thenReturn(mockAuth); + when(ESAPI.class, "randomizer").thenReturn(mockRand); + + when(mockRequest.getSession(false)).thenReturn(mockSession); + when(mockSession.getAttribute(ESAPI_SESSION_ATTR)).thenReturn(testName.getMethodName()+ "-SESSION"); + + //Session value generation + when(mockRand.getRandomInteger(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt())).thenReturn(55555); + + when(mockUser.getLastHostAddress()).thenReturn(testName.getMethodName() + "-HOST_ADDR"); + + + when(mockAuth.getCurrentUser()).thenReturn(mockUser); + } + + @Test + public void testHappyPath() throws Exception { + ClientInfoSupplier cis = new ClientInfoSupplier(); + cis.setLogClientInfo(true); + String result = cis.get(); + + assertEquals(testName.getMethodName() + "-SESSION@"+testName.getMethodName() + "-HOST_ADDR", result); + + verify(mockAuth,times(1)).getCurrentUser(); + verify(mockRequest,times(1)).getSession(false); + verify(mockSession,times(1)).getAttribute(ESAPI_SESSION_ATTR); + verify(mockUser,times(1)).getLastHostAddress(); + + verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser); + } + + @Test + public void testLogUserOff() { + ClientInfoSupplier cis = new ClientInfoSupplier(); + cis.setLogClientInfo(false); + String result = cis.get(); + + assertTrue(result.isEmpty()); + + verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser); + } + + @Test + public void testLogUserNull() { + when(mockAuth.getCurrentUser()).thenReturn(null); + ClientInfoSupplier cis = new ClientInfoSupplier(); + cis.setLogClientInfo(true); + String result = cis.get(); + + assertEquals(testName.getMethodName()+ "-SESSION@#UNKNOWN_HOST#", result); + + verify(mockAuth,times(1)).getCurrentUser(); + verify(mockRequest,times(1)).getSession(false); + verify(mockSession,times(1)).getAttribute(ESAPI_SESSION_ATTR); + + verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser); + } + + @Test + public void testNullRequest() throws Exception { + when(ESAPI.class, "currentRequest").thenReturn(null); + ClientInfoSupplier cis = new ClientInfoSupplier(); + cis.setLogClientInfo(true); + String result = cis.get(); + + //sid is empty when request is null + assertEquals("@"+testName.getMethodName() + "-HOST_ADDR", result); + + verify(mockAuth,times(1)).getCurrentUser(); + verify(mockUser,times(1)).getLastHostAddress(); + + verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser); + } + + @Test + public void testNullSession() throws Exception { + when(mockRequest.getSession(false)).thenReturn(null); + ClientInfoSupplier cis = new ClientInfoSupplier(); + cis.setLogClientInfo(true); + String result = cis.get(); + + //sid is empty when session is null + assertEquals("@"+testName.getMethodName() + "-HOST_ADDR", result); + + + verify(mockAuth,times(1)).getCurrentUser(); + verify(mockRequest,times(1)).getSession(false); + verify(mockUser,times(1)).getLastHostAddress(); + + + verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser); + } + + + + @Test + public void testNullEsapiSession() throws Exception { + when(mockSession.getAttribute(ESAPI_SESSION_ATTR)).thenReturn(null); + ClientInfoSupplier cis = new ClientInfoSupplier(); + cis.setLogClientInfo(true); + String result = cis.get(); + + //sid is empty when session is null + assertEquals("55555@"+testName.getMethodName() + "-HOST_ADDR", result); + + verify(mockAuth,times(1)).getCurrentUser(); + verify(mockRequest,times(1)).getSession(false); + verify(mockSession,times(1)).getAttribute(ESAPI_SESSION_ATTR); + verify(mockSession, times(1)).setAttribute(ESAPI_SESSION_ATTR, (""+55555)); + verify(mockRand, times(1)).getRandomInteger(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt()); + verify(mockUser,times(1)).getLastHostAddress(); + + verifyNoMoreInteractions(mockAuth, mockRand, mockRequest, mockSession, mockUser); + } } \ No newline at end of file diff --git a/src/test/java/org/owasp/esapi/logging/appender/EventTypeLogSupplierTest.java b/src/test/java/org/owasp/esapi/logging/appender/EventTypeLogSupplierTest.java index f86fbbca4..44aeaff70 100644 --- a/src/test/java/org/owasp/esapi/logging/appender/EventTypeLogSupplierTest.java +++ b/src/test/java/org/owasp/esapi/logging/appender/EventTypeLogSupplierTest.java @@ -37,10 +37,10 @@ public EventTypeLogSupplierTest(EventType eventType, String result) { this.eventType = eventType; this.expectedResult = result; } - @Test - public void testEventTypeLog() { - EventTypeLogSupplier supplier = new EventTypeLogSupplier(eventType); - assertEquals(expectedResult, supplier.get()); - } - + @Test + public void testEventTypeLog() { + EventTypeLogSupplier supplier = new EventTypeLogSupplier(eventType); + assertEquals(expectedResult, supplier.get()); + } + } diff --git a/src/test/java/org/owasp/esapi/logging/appender/ServerInfoSupplierTest.java b/src/test/java/org/owasp/esapi/logging/appender/ServerInfoSupplierTest.java index 5280ecb3b..db91b8087 100644 --- a/src/test/java/org/owasp/esapi/logging/appender/ServerInfoSupplierTest.java +++ b/src/test/java/org/owasp/esapi/logging/appender/ServerInfoSupplierTest.java @@ -19,77 +19,77 @@ @RunWith(PowerMockRunner.class) @PrepareForTest({ ESAPI.class }) public class ServerInfoSupplierTest { - @Rule - public TestName testName = new TestName(); - - private HttpServletRequest request; - - @Before - public void buildStaticMocks() throws Exception { - request = mock(HttpServletRequest.class); - mockStatic(ESAPI.class); - when(ESAPI.class, "currentRequest").thenReturn(request); - } - - @Test - public void verifyFullOutput() { - when(request.getLocalAddr()).thenReturn("LOCAL_ADDR"); - when(request.getLocalPort()).thenReturn(99999); - - ServerInfoSupplier sis = new ServerInfoSupplier(testName.getMethodName()); - sis.setLogApplicationName(true, testName.getMethodName() + "-APPLICATION"); - sis.setLogServerIp(true); - - String result = sis.get(); - assertEquals("LOCAL_ADDR:99999/" + testName.getMethodName() + "-APPLICATION/" + testName.getMethodName(), - result); - } - - @Test - public void verifyOutputNullRequest() throws Exception { - when(ESAPI.class, "currentRequest").thenReturn(null); - ServerInfoSupplier sis = new ServerInfoSupplier(testName.getMethodName()); - sis.setLogApplicationName(true, testName.getMethodName() + "-APPLICATION"); - sis.setLogServerIp(true); - - String result = sis.get(); - assertEquals("/" + testName.getMethodName() + "-APPLICATION/" + testName.getMethodName(), result); - } - - @Test - public void verifyOutputNoAppName() { - when(request.getLocalAddr()).thenReturn("LOCAL_ADDR"); - when(request.getLocalPort()).thenReturn(99999); - - ServerInfoSupplier sis = new ServerInfoSupplier(testName.getMethodName()); - sis.setLogApplicationName(false, null); - sis.setLogServerIp(true); - - String result = sis.get(); - assertEquals("LOCAL_ADDR:99999/" + testName.getMethodName(), result); - } - - @Test - public void verifyOutputNullAppName() { - when(request.getLocalAddr()).thenReturn("LOCAL_ADDR"); - when(request.getLocalPort()).thenReturn(99999); - - ServerInfoSupplier sis = new ServerInfoSupplier(testName.getMethodName()); - sis.setLogApplicationName(true, null); - sis.setLogServerIp(true); - - String result = sis.get(); - assertEquals("LOCAL_ADDR:99999/null/" + testName.getMethodName(), result); - } - - @Test - public void verifyOutputNoServerIp() { - ServerInfoSupplier sis = new ServerInfoSupplier(testName.getMethodName()); - sis.setLogApplicationName(true, testName.getMethodName() + "-APPLICATION"); - sis.setLogServerIp(false); - - String result = sis.get(); - assertEquals("/" + testName.getMethodName() + "-APPLICATION/" + testName.getMethodName(), result); - } + @Rule + public TestName testName = new TestName(); + + private HttpServletRequest request; + + @Before + public void buildStaticMocks() throws Exception { + request = mock(HttpServletRequest.class); + mockStatic(ESAPI.class); + when(ESAPI.class, "currentRequest").thenReturn(request); + } + + @Test + public void verifyFullOutput() { + when(request.getLocalAddr()).thenReturn("LOCAL_ADDR"); + when(request.getLocalPort()).thenReturn(99999); + + ServerInfoSupplier sis = new ServerInfoSupplier(testName.getMethodName()); + sis.setLogApplicationName(true, testName.getMethodName() + "-APPLICATION"); + sis.setLogServerIp(true); + + String result = sis.get(); + assertEquals("LOCAL_ADDR:99999/" + testName.getMethodName() + "-APPLICATION/" + testName.getMethodName(), + result); + } + + @Test + public void verifyOutputNullRequest() throws Exception { + when(ESAPI.class, "currentRequest").thenReturn(null); + ServerInfoSupplier sis = new ServerInfoSupplier(testName.getMethodName()); + sis.setLogApplicationName(true, testName.getMethodName() + "-APPLICATION"); + sis.setLogServerIp(true); + + String result = sis.get(); + assertEquals("/" + testName.getMethodName() + "-APPLICATION/" + testName.getMethodName(), result); + } + + @Test + public void verifyOutputNoAppName() { + when(request.getLocalAddr()).thenReturn("LOCAL_ADDR"); + when(request.getLocalPort()).thenReturn(99999); + + ServerInfoSupplier sis = new ServerInfoSupplier(testName.getMethodName()); + sis.setLogApplicationName(false, null); + sis.setLogServerIp(true); + + String result = sis.get(); + assertEquals("LOCAL_ADDR:99999/" + testName.getMethodName(), result); + } + + @Test + public void verifyOutputNullAppName() { + when(request.getLocalAddr()).thenReturn("LOCAL_ADDR"); + when(request.getLocalPort()).thenReturn(99999); + + ServerInfoSupplier sis = new ServerInfoSupplier(testName.getMethodName()); + sis.setLogApplicationName(true, null); + sis.setLogServerIp(true); + + String result = sis.get(); + assertEquals("LOCAL_ADDR:99999/null/" + testName.getMethodName(), result); + } + + @Test + public void verifyOutputNoServerIp() { + ServerInfoSupplier sis = new ServerInfoSupplier(testName.getMethodName()); + sis.setLogApplicationName(true, testName.getMethodName() + "-APPLICATION"); + sis.setLogServerIp(false); + + String result = sis.get(); + assertEquals("/" + testName.getMethodName() + "-APPLICATION/" + testName.getMethodName(), result); + } } diff --git a/src/test/java/org/owasp/esapi/logging/appender/UserInfoSupplierTest.java b/src/test/java/org/owasp/esapi/logging/appender/UserInfoSupplierTest.java index 8ae9decef..db86bb0ff 100644 --- a/src/test/java/org/owasp/esapi/logging/appender/UserInfoSupplierTest.java +++ b/src/test/java/org/owasp/esapi/logging/appender/UserInfoSupplierTest.java @@ -30,66 +30,66 @@ @PrepareForTest({ESAPI.class}) @PowerMockIgnore("javax.security.*") //Required since User extends javax.security.Principal public class UserInfoSupplierTest { - private static final String ESAPI_SESSION_ATTR = "ESAPI_SESSION"; - - @Rule + private static final String ESAPI_SESSION_ATTR = "ESAPI_SESSION"; + + @Rule public TestName testName = new TestName(); - - private Authenticator mockAuth; - private User mockUser; - - @Before - public void before() throws Exception { - mockAuth =mock(Authenticator.class); - mockUser =mock(User.class); - - mockStatic(ESAPI.class); - when(ESAPI.class, "authenticator").thenReturn(mockAuth); - - when(mockUser.getAccountName()).thenReturn(testName.getMethodName() + "-USER"); - - - when(mockAuth.getCurrentUser()).thenReturn(mockUser); - } - - @Test - public void testHappyPath() throws Exception { - UserInfoSupplier uis = new UserInfoSupplier(); - uis.setLogUserInfo(true); - String result = uis.get(); - - assertEquals(testName.getMethodName() + "-USER", result); - - verify(mockAuth,times(1)).getCurrentUser(); - verify(mockUser,times(1)).getAccountName(); - - verifyNoMoreInteractions(mockAuth, mockUser); - } - - @Test - public void testLogUserOff() { - UserInfoSupplier uis = new UserInfoSupplier(); - uis.setLogUserInfo(false); - String result = uis.get(); - - assertTrue(result.isEmpty()); - verify(mockAuth,times(1)).getCurrentUser(); - - verifyNoMoreInteractions(mockAuth, mockUser); - } - - @Test - public void testLogUserNull() { - when(mockAuth.getCurrentUser()).thenReturn(null); - UserInfoSupplier uis = new UserInfoSupplier(); - uis.setLogUserInfo(true); - String result = uis.get(); - - assertEquals("#ANONYMOUS#", result); - - verify(mockAuth,times(1)).getCurrentUser(); - - verifyNoMoreInteractions(mockAuth, mockUser); - } - + + private Authenticator mockAuth; + private User mockUser; + + @Before + public void before() throws Exception { + mockAuth =mock(Authenticator.class); + mockUser =mock(User.class); + + mockStatic(ESAPI.class); + when(ESAPI.class, "authenticator").thenReturn(mockAuth); + + when(mockUser.getAccountName()).thenReturn(testName.getMethodName() + "-USER"); + + + when(mockAuth.getCurrentUser()).thenReturn(mockUser); + } + + @Test + public void testHappyPath() throws Exception { + UserInfoSupplier uis = new UserInfoSupplier(); + uis.setLogUserInfo(true); + String result = uis.get(); + + assertEquals(testName.getMethodName() + "-USER", result); + + verify(mockAuth,times(1)).getCurrentUser(); + verify(mockUser,times(1)).getAccountName(); + + verifyNoMoreInteractions(mockAuth, mockUser); + } + + @Test + public void testLogUserOff() { + UserInfoSupplier uis = new UserInfoSupplier(); + uis.setLogUserInfo(false); + String result = uis.get(); + + assertTrue(result.isEmpty()); + verify(mockAuth,times(1)).getCurrentUser(); + + verifyNoMoreInteractions(mockAuth, mockUser); + } + + @Test + public void testLogUserNull() { + when(mockAuth.getCurrentUser()).thenReturn(null); + UserInfoSupplier uis = new UserInfoSupplier(); + uis.setLogUserInfo(true); + String result = uis.get(); + + assertEquals("#ANONYMOUS#", result); + + verify(mockAuth,times(1)).getCurrentUser(); + + verifyNoMoreInteractions(mockAuth, mockUser); + } + } \ No newline at end of file diff --git a/src/test/java/org/owasp/esapi/logging/java/JavaLogFactoryTest.java b/src/test/java/org/owasp/esapi/logging/java/JavaLogFactoryTest.java index 465083da3..2cdcdcc43 100644 --- a/src/test/java/org/owasp/esapi/logging/java/JavaLogFactoryTest.java +++ b/src/test/java/org/owasp/esapi/logging/java/JavaLogFactoryTest.java @@ -134,7 +134,7 @@ public void checkPassthroughAppenderConstruct() throws Exception { Assert.assertTrue(clientInfoCapture.getValue()); Assert.assertFalse(serverInfoCapture.getValue()); Assert.assertTrue(logAppNameCapture.getValue()); - Assert.assertEquals(testName.getMethodName(), appNameCapture.getValue()); + Assert.assertEquals(testName.getMethodName(), appNameCapture.getValue()); } diff --git a/src/test/java/org/owasp/esapi/logging/log4j/Log4JLogFactoryTest.java b/src/test/java/org/owasp/esapi/logging/log4j/Log4JLogFactoryTest.java index 3b7378996..3e186480d 100644 --- a/src/test/java/org/owasp/esapi/logging/log4j/Log4JLogFactoryTest.java +++ b/src/test/java/org/owasp/esapi/logging/log4j/Log4JLogFactoryTest.java @@ -101,7 +101,7 @@ public void checkPassthroughAppenderConstruct() throws Exception { Assert.assertTrue(clientInfoCapture.getValue()); Assert.assertFalse(serverInfoCapture.getValue()); Assert.assertTrue(logAppNameCapture.getValue()); - Assert.assertEquals(testName.getMethodName(), appNameCapture.getValue()); + Assert.assertEquals(testName.getMethodName(), appNameCapture.getValue()); } diff --git a/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLogBridgeImplTest.java b/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLogBridgeImplTest.java index f9586a85a..b5674b3e8 100644 --- a/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLogBridgeImplTest.java +++ b/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLogBridgeImplTest.java @@ -73,10 +73,10 @@ public void testLogMessageAndExceptionWithUnmappedEsapiLevelThrowsException() { @Test public void testLogMessage() { - EventType eventType = Logger.EVENT_UNSPECIFIED; - String loggerName = testName.getMethodName() + "-LOGGER"; - String orignMsg = testName.getMethodName(); - String appendMsg = "[APPEND] " + orignMsg; + EventType eventType = Logger.EVENT_UNSPECIFIED; + String loggerName = testName.getMethodName() + "-LOGGER"; + String orignMsg = testName.getMethodName(); + String appendMsg = "[APPEND] " + orignMsg; String cleanMsg = appendMsg + " [CLEANED]"; //Setup for Appender @@ -103,10 +103,10 @@ public void testLogMessage() { @Test public void testLogErrorMessageWithException() { - EventType eventType = Logger.EVENT_UNSPECIFIED; - String loggerName = testName.getMethodName() + "-LOGGER"; - String orignMsg = testName.getMethodName(); - String appendMsg = "[APPEND] " + orignMsg; + EventType eventType = Logger.EVENT_UNSPECIFIED; + String loggerName = testName.getMethodName() + "-LOGGER"; + String orignMsg = testName.getMethodName(); + String appendMsg = "[APPEND] " + orignMsg; String cleanMsg = appendMsg + " [CLEANED]"; //Setup for Appender diff --git a/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLogFactoryTest.java b/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLogFactoryTest.java index c392f1d23..f7e4b13fe 100644 --- a/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLogFactoryTest.java +++ b/src/test/java/org/owasp/esapi/logging/slf4j/Slf4JLogFactoryTest.java @@ -36,9 +36,9 @@ @RunWith(PowerMockRunner.class) @PrepareForTest (Slf4JLogFactory.class) public class Slf4JLogFactoryTest { - @Rule + @Rule public TestName testName = new TestName(); - + @Test public void testCreateLoggerByString() { Logger logger = new Slf4JLogFactory().getLogger("test"); @@ -78,11 +78,11 @@ public void checkScrubberWithoutEncoding() throws Exception { } /** - * At this time there are no special considerations or handling for the appender - * creation in this scope. It is expected that the arguments to the internal - * creation method are passed directly to the constructor of the - * LogPrefixAppender with no mutation or additional validation. - */ + * At this time there are no special considerations or handling for the appender + * creation in this scope. It is expected that the arguments to the internal + * creation method are passed directly to the constructor of the + * LogPrefixAppender with no mutation or additional validation. + */ @Test public void checkPassthroughAppenderConstruct() throws Exception { LogPrefixAppender stubAppender = new LogPrefixAppender(true, true, true, true, ""); @@ -94,14 +94,14 @@ public void checkPassthroughAppenderConstruct() throws Exception { PowerMockito.whenNew(LogPrefixAppender.class).withArguments(userInfoCapture.capture(), clientInfoCapture.capture(), serverInfoCapture.capture(), logAppNameCapture.capture(), appNameCapture.capture()).thenReturn(stubAppender); - LogAppender appender = Slf4JLogFactory.createLogAppender(true, true, false, true, testName.getMethodName()); - - Assert.assertEquals(stubAppender, appender); - Assert.assertTrue(userInfoCapture.getValue()); - Assert.assertTrue(clientInfoCapture.getValue()); - Assert.assertFalse(serverInfoCapture.getValue()); - Assert.assertTrue(logAppNameCapture.getValue()); - Assert.assertEquals(testName.getMethodName(), appNameCapture.getValue()); + LogAppender appender = Slf4JLogFactory.createLogAppender(true, true, false, true, testName.getMethodName()); + + Assert.assertEquals(stubAppender, appender); + Assert.assertTrue(userInfoCapture.getValue()); + Assert.assertTrue(clientInfoCapture.getValue()); + Assert.assertFalse(serverInfoCapture.getValue()); + Assert.assertTrue(logAppNameCapture.getValue()); + Assert.assertEquals(testName.getMethodName(), appNameCapture.getValue()); } diff --git a/src/test/java/org/owasp/esapi/reference/AccessControllerTest.java b/src/test/java/org/owasp/esapi/reference/AccessControllerTest.java index 107c1da71..abee34afa 100644 --- a/src/test/java/org/owasp/esapi/reference/AccessControllerTest.java +++ b/src/test/java/org/owasp/esapi/reference/AccessControllerTest.java @@ -33,326 +33,326 @@ */ public class AccessControllerTest extends TestCase { - /** - * Instantiates a new access controller test. - * - * @param testName + /** + * Instantiates a new access controller test. + * + * @param testName * the test name * @throws Exception - */ - public AccessControllerTest(String testName) throws Exception { - super(testName); - - Authenticator authenticator = ESAPI.authenticator(); - String password = authenticator.generateStrongPassword(); + */ + public AccessControllerTest(String testName) throws Exception { + super(testName); + + Authenticator authenticator = ESAPI.authenticator(); + String password = authenticator.generateStrongPassword(); - // create a user with the "user" role for this test - User alice = authenticator.getUser("testuser1"); - if ( alice == null ) { - alice = authenticator.createUser( "testuser1", password, password); - } - alice.addRole("user"); + // create a user with the "user" role for this test + User alice = authenticator.getUser("testuser1"); + if ( alice == null ) { + alice = authenticator.createUser( "testuser1", password, password); + } + alice.addRole("user"); - // create a user with the "admin" role for this test - User bob = authenticator.getUser("testuser2"); - if ( bob == null ) { - bob = authenticator.createUser( "testuser2", password, password); - } - bob.addRole("admin"); - - // create a user with the "user" and "admin" roles for this test - User mitch = authenticator.getUser("testuser3"); - if ( mitch == null ) { - mitch = authenticator.createUser( "testuser3", password, password); - } - mitch.addRole("admin"); - mitch.addRole("user"); - } + // create a user with the "admin" role for this test + User bob = authenticator.getUser("testuser2"); + if ( bob == null ) { + bob = authenticator.createUser( "testuser2", password, password); + } + bob.addRole("admin"); + + // create a user with the "user" and "admin" roles for this test + User mitch = authenticator.getUser("testuser3"); + if ( mitch == null ) { + mitch = authenticator.createUser( "testuser3", password, password); + } + mitch.addRole("admin"); + mitch.addRole("user"); + } /** * {@inheritDoc} * * @throws Exception */ - protected void setUp() throws Exception { - } + protected void setUp() throws Exception { + } /** * {@inheritDoc} * * @throws Exception */ - protected void tearDown() throws Exception { - // none - } + protected void tearDown() throws Exception { + // none + } - /** - * Suite. - * - * @return the test - */ - public static Test suite() { - TestSuite suite = new TestSuite(AccessControllerTest.class); - return suite; - } + /** + * Suite. + * + * @return the test + */ + public static Test suite() { + TestSuite suite = new TestSuite(AccessControllerTest.class); + return suite; + } /** * */ public void testMatchRule() { - ESAPI.authenticator().setCurrentUser(null); - assertFalse(ESAPI.accessController().isAuthorizedForURL("/nobody")); - } - - /** - * Test of isAuthorizedForURL method, of class - * org.owasp.esapi.AccessController. + ESAPI.authenticator().setCurrentUser(null); + assertFalse(ESAPI.accessController().isAuthorizedForURL("/nobody")); + } + + /** + * Test of isAuthorizedForURL method, of class + * org.owasp.esapi.AccessController. * * @throws Exception */ - public void testIsAuthorizedForURL() throws Exception { - System.out.println("isAuthorizedForURL"); - AccessController instance = ESAPI.accessController(); - Authenticator auth = ESAPI.authenticator(); - - auth.setCurrentUser( auth.getUser("testuser1") ); - assertFalse(instance.isAuthorizedForURL("/nobody")); - assertFalse(instance.isAuthorizedForURL("/test/admin")); - assertTrue(instance.isAuthorizedForURL("/test/user")); - assertTrue(instance.isAuthorizedForURL("/test/all")); - assertFalse(instance.isAuthorizedForURL("/test/none")); - assertTrue(instance.isAuthorizedForURL("/test/none/test.gif")); - assertFalse(instance.isAuthorizedForURL("/test/none/test.exe")); - assertTrue(instance.isAuthorizedForURL("/test/none/test.png")); - assertFalse(instance.isAuthorizedForURL("/test/moderator")); - assertTrue(instance.isAuthorizedForURL("/test/profile")); - assertFalse(instance.isAuthorizedForURL("/upload")); + public void testIsAuthorizedForURL() throws Exception { + System.out.println("isAuthorizedForURL"); + AccessController instance = ESAPI.accessController(); + Authenticator auth = ESAPI.authenticator(); + + auth.setCurrentUser( auth.getUser("testuser1") ); + assertFalse(instance.isAuthorizedForURL("/nobody")); + assertFalse(instance.isAuthorizedForURL("/test/admin")); + assertTrue(instance.isAuthorizedForURL("/test/user")); + assertTrue(instance.isAuthorizedForURL("/test/all")); + assertFalse(instance.isAuthorizedForURL("/test/none")); + assertTrue(instance.isAuthorizedForURL("/test/none/test.gif")); + assertFalse(instance.isAuthorizedForURL("/test/none/test.exe")); + assertTrue(instance.isAuthorizedForURL("/test/none/test.png")); + assertFalse(instance.isAuthorizedForURL("/test/moderator")); + assertTrue(instance.isAuthorizedForURL("/test/profile")); + assertFalse(instance.isAuthorizedForURL("/upload")); - auth.setCurrentUser( auth.getUser("testuser2") ); - assertFalse(instance.isAuthorizedForURL("/nobody")); - assertTrue(instance.isAuthorizedForURL("/test/admin")); - assertFalse(instance.isAuthorizedForURL("/test/user")); - assertTrue(instance.isAuthorizedForURL("/test/all")); - assertFalse(instance.isAuthorizedForURL("/test/none")); - assertTrue(instance.isAuthorizedForURL("/test/none/test.png")); - assertFalse(instance.isAuthorizedForURL("/test/moderator")); - assertTrue(instance.isAuthorizedForURL("/test/profile")); - assertFalse(instance.isAuthorizedForURL("/upload")); - - auth.setCurrentUser( auth.getUser("testuser3") ); - assertFalse(instance.isAuthorizedForURL("/nobody")); - assertTrue(instance.isAuthorizedForURL("/test/admin")); - assertTrue(instance.isAuthorizedForURL("/test/user")); - assertTrue(instance.isAuthorizedForURL("/test/all")); - assertFalse(instance.isAuthorizedForURL("/test/none")); - assertTrue(instance.isAuthorizedForURL("/test/none/test.png")); - assertFalse(instance.isAuthorizedForURL("/test/moderator")); - assertTrue(instance.isAuthorizedForURL("/test/profile")); - assertFalse(instance.isAuthorizedForURL("/upload")); - - try { - instance.assertAuthorizedForURL("/test/admin"); - instance.assertAuthorizedForURL( "/nobody" ); - fail(); - } catch ( AccessControlException e ) { - // expected - } - } + auth.setCurrentUser( auth.getUser("testuser2") ); + assertFalse(instance.isAuthorizedForURL("/nobody")); + assertTrue(instance.isAuthorizedForURL("/test/admin")); + assertFalse(instance.isAuthorizedForURL("/test/user")); + assertTrue(instance.isAuthorizedForURL("/test/all")); + assertFalse(instance.isAuthorizedForURL("/test/none")); + assertTrue(instance.isAuthorizedForURL("/test/none/test.png")); + assertFalse(instance.isAuthorizedForURL("/test/moderator")); + assertTrue(instance.isAuthorizedForURL("/test/profile")); + assertFalse(instance.isAuthorizedForURL("/upload")); + + auth.setCurrentUser( auth.getUser("testuser3") ); + assertFalse(instance.isAuthorizedForURL("/nobody")); + assertTrue(instance.isAuthorizedForURL("/test/admin")); + assertTrue(instance.isAuthorizedForURL("/test/user")); + assertTrue(instance.isAuthorizedForURL("/test/all")); + assertFalse(instance.isAuthorizedForURL("/test/none")); + assertTrue(instance.isAuthorizedForURL("/test/none/test.png")); + assertFalse(instance.isAuthorizedForURL("/test/moderator")); + assertTrue(instance.isAuthorizedForURL("/test/profile")); + assertFalse(instance.isAuthorizedForURL("/upload")); + + try { + instance.assertAuthorizedForURL("/test/admin"); + instance.assertAuthorizedForURL( "/nobody" ); + fail(); + } catch ( AccessControlException e ) { + // expected + } + } - /** - * Test of isAuthorizedForFunction method, of class - * org.owasp.esapi.AccessController. - */ - public void testIsAuthorizedForFunction() { - System.out.println("isAuthorizedForFunction"); - AccessController instance = ESAPI.accessController(); - Authenticator auth = ESAPI.authenticator(); - - auth.setCurrentUser( auth.getUser("testuser1") ); - assertTrue(instance.isAuthorizedForFunction("/FunctionA")); - assertFalse(instance.isAuthorizedForFunction("/FunctionAdeny")); - assertFalse(instance.isAuthorizedForFunction("/FunctionB")); - assertFalse(instance.isAuthorizedForFunction("/FunctionBdeny")); - assertTrue(instance.isAuthorizedForFunction("/FunctionC")); - assertFalse(instance.isAuthorizedForFunction("/FunctionCdeny")); + /** + * Test of isAuthorizedForFunction method, of class + * org.owasp.esapi.AccessController. + */ + public void testIsAuthorizedForFunction() { + System.out.println("isAuthorizedForFunction"); + AccessController instance = ESAPI.accessController(); + Authenticator auth = ESAPI.authenticator(); + + auth.setCurrentUser( auth.getUser("testuser1") ); + assertTrue(instance.isAuthorizedForFunction("/FunctionA")); + assertFalse(instance.isAuthorizedForFunction("/FunctionAdeny")); + assertFalse(instance.isAuthorizedForFunction("/FunctionB")); + assertFalse(instance.isAuthorizedForFunction("/FunctionBdeny")); + assertTrue(instance.isAuthorizedForFunction("/FunctionC")); + assertFalse(instance.isAuthorizedForFunction("/FunctionCdeny")); - auth.setCurrentUser( auth.getUser("testuser2") ); - assertFalse(instance.isAuthorizedForFunction("/FunctionA")); - assertFalse(instance.isAuthorizedForFunction("/FunctionAdeny")); - assertTrue(instance.isAuthorizedForFunction("/FunctionB")); - assertFalse(instance.isAuthorizedForFunction("/FunctionBdeny")); - assertTrue(instance.isAuthorizedForFunction("/FunctionD")); - assertFalse(instance.isAuthorizedForFunction("/FunctionDdeny")); + auth.setCurrentUser( auth.getUser("testuser2") ); + assertFalse(instance.isAuthorizedForFunction("/FunctionA")); + assertFalse(instance.isAuthorizedForFunction("/FunctionAdeny")); + assertTrue(instance.isAuthorizedForFunction("/FunctionB")); + assertFalse(instance.isAuthorizedForFunction("/FunctionBdeny")); + assertTrue(instance.isAuthorizedForFunction("/FunctionD")); + assertFalse(instance.isAuthorizedForFunction("/FunctionDdeny")); - auth.setCurrentUser( auth.getUser("testuser3") ); - assertTrue(instance.isAuthorizedForFunction("/FunctionA")); - assertFalse(instance.isAuthorizedForFunction("/FunctionAdeny")); - assertTrue(instance.isAuthorizedForFunction("/FunctionB")); - assertFalse(instance.isAuthorizedForFunction("/FunctionBdeny")); - assertTrue(instance.isAuthorizedForFunction("/FunctionC")); - assertFalse(instance.isAuthorizedForFunction("/FunctionCdeny")); + auth.setCurrentUser( auth.getUser("testuser3") ); + assertTrue(instance.isAuthorizedForFunction("/FunctionA")); + assertFalse(instance.isAuthorizedForFunction("/FunctionAdeny")); + assertTrue(instance.isAuthorizedForFunction("/FunctionB")); + assertFalse(instance.isAuthorizedForFunction("/FunctionBdeny")); + assertTrue(instance.isAuthorizedForFunction("/FunctionC")); + assertFalse(instance.isAuthorizedForFunction("/FunctionCdeny")); - try { - instance.assertAuthorizedForFunction("/FunctionA"); - instance.assertAuthorizedForFunction( "/FunctionDdeny" ); - fail(); - } catch ( AccessControlException e ) { - // expected - } - } + try { + instance.assertAuthorizedForFunction("/FunctionA"); + instance.assertAuthorizedForFunction( "/FunctionDdeny" ); + fail(); + } catch ( AccessControlException e ) { + // expected + } + } - /** - * Test of isAuthorizedForData method, of class - * org.owasp.esapi.AccessController. - */ - public void testIsAuthorizedForData() { - System.out.println("isAuthorizedForData"); - AccessController instance = ESAPI.accessController(); - Authenticator auth = ESAPI.authenticator(); - - Class adminR = null; - Class adminRW = null; - Class userW = null; - Class userRW = null; - Class anyR = null; - Class userAdminR = null; - Class userAdminRW = null; - Class undefined = null; - - try{ - adminR = Class.forName("java.util.ArrayList"); - adminRW = Class.forName("java.lang.Math"); - userW = Class.forName("java.util.Date"); - userRW = Class.forName("java.lang.String"); - anyR = Class.forName("java.io.BufferedReader"); - userAdminR = Class.forName("java.util.Random"); - userAdminRW = Class.forName("javax.crypto.Cipher"); - undefined = Class.forName("java.io.FileWriter"); - - }catch(ClassNotFoundException cnf){ - System.out.println("CLASS NOT FOUND."); - cnf.printStackTrace(); - } - //test User - auth.setCurrentUser( auth.getUser("testuser1") ); - assertTrue(instance.isAuthorizedForData("read", userRW)); - assertFalse(instance.isAuthorizedForData("read", undefined)); - assertFalse(instance.isAuthorizedForData("write", undefined)); - assertFalse(instance.isAuthorizedForData("read", userW)); - assertFalse(instance.isAuthorizedForData("read", adminRW)); - assertTrue(instance.isAuthorizedForData("write", userRW)); - assertTrue(instance.isAuthorizedForData("write", userW)); - assertFalse(instance.isAuthorizedForData("write", anyR)); - assertTrue(instance.isAuthorizedForData("read", anyR)); - assertTrue(instance.isAuthorizedForData("read", userAdminR)); - assertTrue(instance.isAuthorizedForData("write", userAdminRW)); - - //test Admin - auth.setCurrentUser( auth.getUser("testuser2") ); - assertTrue(instance.isAuthorizedForData("read", adminRW)); - assertFalse(instance.isAuthorizedForData("read", undefined)); - assertFalse(instance.isAuthorizedForData("write", undefined)); - assertFalse(instance.isAuthorizedForData("read", userRW)); - assertTrue(instance.isAuthorizedForData("write", adminRW)); - assertFalse(instance.isAuthorizedForData("write", anyR)); - assertTrue(instance.isAuthorizedForData("read", anyR)); - assertTrue(instance.isAuthorizedForData("read", userAdminR)); - assertTrue(instance.isAuthorizedForData("write", userAdminRW)); - - //test User/Admin - auth.setCurrentUser( auth.getUser("testuser3") ); - assertTrue(instance.isAuthorizedForData("read", userRW)); - assertFalse(instance.isAuthorizedForData("read", undefined)); - assertFalse(instance.isAuthorizedForData("write", undefined)); - assertFalse(instance.isAuthorizedForData("read", userW)); - assertTrue(instance.isAuthorizedForData("read", adminR)); - assertTrue(instance.isAuthorizedForData("write", userRW)); - assertTrue(instance.isAuthorizedForData("write", userW)); - assertFalse(instance.isAuthorizedForData("write", anyR)); - assertTrue(instance.isAuthorizedForData("read", anyR)); - assertTrue(instance.isAuthorizedForData("read", userAdminR)); - assertTrue(instance.isAuthorizedForData("write", userAdminRW)); - try { - instance.assertAuthorizedForData("read", userRW); - instance.assertAuthorizedForData( "write", adminR ); - fail(); - } catch ( AccessControlException e ) { - // expected - } - - } + /** + * Test of isAuthorizedForData method, of class + * org.owasp.esapi.AccessController. + */ + public void testIsAuthorizedForData() { + System.out.println("isAuthorizedForData"); + AccessController instance = ESAPI.accessController(); + Authenticator auth = ESAPI.authenticator(); + + Class adminR = null; + Class adminRW = null; + Class userW = null; + Class userRW = null; + Class anyR = null; + Class userAdminR = null; + Class userAdminRW = null; + Class undefined = null; + + try{ + adminR = Class.forName("java.util.ArrayList"); + adminRW = Class.forName("java.lang.Math"); + userW = Class.forName("java.util.Date"); + userRW = Class.forName("java.lang.String"); + anyR = Class.forName("java.io.BufferedReader"); + userAdminR = Class.forName("java.util.Random"); + userAdminRW = Class.forName("javax.crypto.Cipher"); + undefined = Class.forName("java.io.FileWriter"); + + }catch(ClassNotFoundException cnf){ + System.out.println("CLASS NOT FOUND."); + cnf.printStackTrace(); + } + //test User + auth.setCurrentUser( auth.getUser("testuser1") ); + assertTrue(instance.isAuthorizedForData("read", userRW)); + assertFalse(instance.isAuthorizedForData("read", undefined)); + assertFalse(instance.isAuthorizedForData("write", undefined)); + assertFalse(instance.isAuthorizedForData("read", userW)); + assertFalse(instance.isAuthorizedForData("read", adminRW)); + assertTrue(instance.isAuthorizedForData("write", userRW)); + assertTrue(instance.isAuthorizedForData("write", userW)); + assertFalse(instance.isAuthorizedForData("write", anyR)); + assertTrue(instance.isAuthorizedForData("read", anyR)); + assertTrue(instance.isAuthorizedForData("read", userAdminR)); + assertTrue(instance.isAuthorizedForData("write", userAdminRW)); + + //test Admin + auth.setCurrentUser( auth.getUser("testuser2") ); + assertTrue(instance.isAuthorizedForData("read", adminRW)); + assertFalse(instance.isAuthorizedForData("read", undefined)); + assertFalse(instance.isAuthorizedForData("write", undefined)); + assertFalse(instance.isAuthorizedForData("read", userRW)); + assertTrue(instance.isAuthorizedForData("write", adminRW)); + assertFalse(instance.isAuthorizedForData("write", anyR)); + assertTrue(instance.isAuthorizedForData("read", anyR)); + assertTrue(instance.isAuthorizedForData("read", userAdminR)); + assertTrue(instance.isAuthorizedForData("write", userAdminRW)); + + //test User/Admin + auth.setCurrentUser( auth.getUser("testuser3") ); + assertTrue(instance.isAuthorizedForData("read", userRW)); + assertFalse(instance.isAuthorizedForData("read", undefined)); + assertFalse(instance.isAuthorizedForData("write", undefined)); + assertFalse(instance.isAuthorizedForData("read", userW)); + assertTrue(instance.isAuthorizedForData("read", adminR)); + assertTrue(instance.isAuthorizedForData("write", userRW)); + assertTrue(instance.isAuthorizedForData("write", userW)); + assertFalse(instance.isAuthorizedForData("write", anyR)); + assertTrue(instance.isAuthorizedForData("read", anyR)); + assertTrue(instance.isAuthorizedForData("read", userAdminR)); + assertTrue(instance.isAuthorizedForData("write", userAdminRW)); + try { + instance.assertAuthorizedForData("read", userRW); + instance.assertAuthorizedForData( "write", adminR ); + fail(); + } catch ( AccessControlException e ) { + // expected + } + + } - /** - * Test of isAuthorizedForFile method, of class - * org.owasp.esapi.AccessController. - */ - public void testIsAuthorizedForFile() { - System.out.println("isAuthorizedForFile"); - AccessController instance = ESAPI.accessController(); - Authenticator auth = ESAPI.authenticator(); - - auth.setCurrentUser( auth.getUser("testuser1") ); - assertTrue(instance.isAuthorizedForFile("/Dir/File1")); - assertFalse(instance.isAuthorizedForFile("/Dir/File2")); - assertTrue(instance.isAuthorizedForFile("/Dir/File3")); - assertFalse(instance.isAuthorizedForFile("/Dir/ridiculous")); + /** + * Test of isAuthorizedForFile method, of class + * org.owasp.esapi.AccessController. + */ + public void testIsAuthorizedForFile() { + System.out.println("isAuthorizedForFile"); + AccessController instance = ESAPI.accessController(); + Authenticator auth = ESAPI.authenticator(); + + auth.setCurrentUser( auth.getUser("testuser1") ); + assertTrue(instance.isAuthorizedForFile("/Dir/File1")); + assertFalse(instance.isAuthorizedForFile("/Dir/File2")); + assertTrue(instance.isAuthorizedForFile("/Dir/File3")); + assertFalse(instance.isAuthorizedForFile("/Dir/ridiculous")); - auth.setCurrentUser( auth.getUser("testuser2") ); - assertFalse(instance.isAuthorizedForFile("/Dir/File1")); - assertTrue(instance.isAuthorizedForFile("/Dir/File2")); - assertTrue(instance.isAuthorizedForFile("/Dir/File4")); - assertFalse(instance.isAuthorizedForFile("/Dir/ridiculous")); + auth.setCurrentUser( auth.getUser("testuser2") ); + assertFalse(instance.isAuthorizedForFile("/Dir/File1")); + assertTrue(instance.isAuthorizedForFile("/Dir/File2")); + assertTrue(instance.isAuthorizedForFile("/Dir/File4")); + assertFalse(instance.isAuthorizedForFile("/Dir/ridiculous")); - auth.setCurrentUser( auth.getUser("testuser3") ); - assertTrue(instance.isAuthorizedForFile("/Dir/File1")); - assertTrue(instance.isAuthorizedForFile("/Dir/File2")); - assertFalse(instance.isAuthorizedForFile("/Dir/File5")); - assertFalse(instance.isAuthorizedForFile("/Dir/ridiculous")); + auth.setCurrentUser( auth.getUser("testuser3") ); + assertTrue(instance.isAuthorizedForFile("/Dir/File1")); + assertTrue(instance.isAuthorizedForFile("/Dir/File2")); + assertFalse(instance.isAuthorizedForFile("/Dir/File5")); + assertFalse(instance.isAuthorizedForFile("/Dir/ridiculous")); - try { - instance.assertAuthorizedForFile("/Dir/File1"); - instance.assertAuthorizedForFile( "/Dir/File6" ); - fail(); - } catch ( AccessControlException e ) { - // expected - } - } + try { + instance.assertAuthorizedForFile("/Dir/File1"); + instance.assertAuthorizedForFile( "/Dir/File6" ); + fail(); + } catch ( AccessControlException e ) { + // expected + } + } - /** - * Test of isAuthorizedForService method, of class - * org.owasp.esapi.AccessController. - */ - public void testIsAuthorizedForService() { - System.out.println("isAuthorizedForService"); - AccessController instance = ESAPI.accessController(); - Authenticator auth = ESAPI.authenticator(); - - auth.setCurrentUser( auth.getUser("testuser1") ); - assertTrue(instance.isAuthorizedForService("/services/ServiceA")); - assertFalse(instance.isAuthorizedForService("/services/ServiceB")); - assertTrue(instance.isAuthorizedForService("/services/ServiceC")); - - assertFalse(instance.isAuthorizedForService("/test/ridiculous")); + /** + * Test of isAuthorizedForService method, of class + * org.owasp.esapi.AccessController. + */ + public void testIsAuthorizedForService() { + System.out.println("isAuthorizedForService"); + AccessController instance = ESAPI.accessController(); + Authenticator auth = ESAPI.authenticator(); + + auth.setCurrentUser( auth.getUser("testuser1") ); + assertTrue(instance.isAuthorizedForService("/services/ServiceA")); + assertFalse(instance.isAuthorizedForService("/services/ServiceB")); + assertTrue(instance.isAuthorizedForService("/services/ServiceC")); + + assertFalse(instance.isAuthorizedForService("/test/ridiculous")); - auth.setCurrentUser( auth.getUser("testuser2") ); - assertFalse(instance.isAuthorizedForService("/services/ServiceA")); - assertTrue(instance.isAuthorizedForService("/services/ServiceB")); - assertFalse(instance.isAuthorizedForService("/services/ServiceF")); - assertFalse(instance.isAuthorizedForService("/test/ridiculous")); + auth.setCurrentUser( auth.getUser("testuser2") ); + assertFalse(instance.isAuthorizedForService("/services/ServiceA")); + assertTrue(instance.isAuthorizedForService("/services/ServiceB")); + assertFalse(instance.isAuthorizedForService("/services/ServiceF")); + assertFalse(instance.isAuthorizedForService("/test/ridiculous")); - auth.setCurrentUser( auth.getUser("testuser3") ); - assertTrue(instance.isAuthorizedForService("/services/ServiceA")); - assertTrue(instance.isAuthorizedForService("/services/ServiceB")); - assertFalse(instance.isAuthorizedForService("/services/ServiceE")); - assertFalse(instance.isAuthorizedForService("/test/ridiculous")); + auth.setCurrentUser( auth.getUser("testuser3") ); + assertTrue(instance.isAuthorizedForService("/services/ServiceA")); + assertTrue(instance.isAuthorizedForService("/services/ServiceB")); + assertFalse(instance.isAuthorizedForService("/services/ServiceE")); + assertFalse(instance.isAuthorizedForService("/test/ridiculous")); - try { - instance.assertAuthorizedForService("/services/ServiceD"); - instance.assertAuthorizedForService( "/test/ridiculous" ); - fail(); - } catch ( AccessControlException e ) { - // expected - } - } + try { + instance.assertAuthorizedForService("/services/ServiceD"); + instance.assertAuthorizedForService( "/test/ridiculous" ); + fail(); + } catch ( AccessControlException e ) { + // expected + } + } } diff --git a/src/test/java/org/owasp/esapi/reference/AccessReferenceMapTest.java b/src/test/java/org/owasp/esapi/reference/AccessReferenceMapTest.java index 1a26077ec..8c479b813 100644 --- a/src/test/java/org/owasp/esapi/reference/AccessReferenceMapTest.java +++ b/src/test/java/org/owasp/esapi/reference/AccessReferenceMapTest.java @@ -39,11 +39,11 @@ public class AccessReferenceMapTest extends TestCase { /** - * Instantiates a new access reference map test. - * - * @param testName - * the test name - */ + * Instantiates a new access reference map test. + * + * @param testName + * the test name + */ public AccessReferenceMapTest(String testName) { super(testName); } @@ -53,7 +53,7 @@ public AccessReferenceMapTest(String testName) { * @throws Exception */ protected void setUp() throws Exception { - // none + // none } /** @@ -61,14 +61,14 @@ protected void setUp() throws Exception { * @throws Exception */ protected void tearDown() throws Exception { - // none + // none } /** - * Suite. - * - * @return the test - */ + * Suite. + * + * @return the test + */ public static Test suite() { TestSuite suite = new TestSuite(AccessReferenceMapTest.class); return suite; @@ -76,60 +76,60 @@ public static Test suite() { /** - * Test of update method, of class org.owasp.esapi.AccessReferenceMap. - * - * @throws AuthenticationException + * Test of update method, of class org.owasp.esapi.AccessReferenceMap. + * + * @throws AuthenticationException * the authentication exception * @throws EncryptionException - */ + */ public void testUpdate() throws AuthenticationException, EncryptionException { System.out.println("update"); - RandomAccessReferenceMap arm = new RandomAccessReferenceMap(); - Authenticator auth = ESAPI.authenticator(); - - String pass = auth.generateStrongPassword(); - User u = auth.createUser( "armUpdate", pass, pass ); - - // test to make sure update returns something - arm.update(auth.getUserNames()); - String indirect = arm.getIndirectReference( u.getAccountName() ); - if ( indirect == null ) fail(); - - // test to make sure update removes items that are no longer in the list - auth.removeUser( u.getAccountName() ); - arm.update(auth.getUserNames()); - indirect = arm.getIndirectReference( u.getAccountName() ); - if ( indirect != null ) fail(); - - // test to make sure old indirect reference is maintained after an update - arm.update(auth.getUserNames()); - String newIndirect = arm.getIndirectReference( u.getAccountName() ); - assertEquals(indirect, newIndirect); + RandomAccessReferenceMap arm = new RandomAccessReferenceMap(); + Authenticator auth = ESAPI.authenticator(); + + String pass = auth.generateStrongPassword(); + User u = auth.createUser( "armUpdate", pass, pass ); + + // test to make sure update returns something + arm.update(auth.getUserNames()); + String indirect = arm.getIndirectReference( u.getAccountName() ); + if ( indirect == null ) fail(); + + // test to make sure update removes items that are no longer in the list + auth.removeUser( u.getAccountName() ); + arm.update(auth.getUserNames()); + indirect = arm.getIndirectReference( u.getAccountName() ); + if ( indirect != null ) fail(); + + // test to make sure old indirect reference is maintained after an update + arm.update(auth.getUserNames()); + String newIndirect = arm.getIndirectReference( u.getAccountName() ); + assertEquals(indirect, newIndirect); } /** - * Test of iterator method, of class org.owasp.esapi.AccessReferenceMap. - */ + * Test of iterator method, of class org.owasp.esapi.AccessReferenceMap. + */ public void testIterator() { System.out.println("iterator"); - RandomAccessReferenceMap arm = new RandomAccessReferenceMap(); + RandomAccessReferenceMap arm = new RandomAccessReferenceMap(); Authenticator auth = ESAPI.authenticator(); - arm.update(auth.getUserNames()); + arm.update(auth.getUserNames()); - Iterator i = arm.iterator(); - while ( i.hasNext() ) { - String userName = (String)i.next(); - User u = auth.getUser( userName ); - if ( u == null ) fail(); - } + Iterator i = arm.iterator(); + while ( i.hasNext() ) { + String userName = (String)i.next(); + User u = auth.getUser( userName ); + if ( u == null ) fail(); + } } /** - * Test of getIndirectReference method, of class - * org.owasp.esapi.AccessReferenceMap. - */ + * Test of getIndirectReference method, of class + * org.owasp.esapi.AccessReferenceMap. + */ public void testGetIndirectReference() { System.out.println("getIndirectReference"); @@ -146,12 +146,12 @@ public void testGetIndirectReference() { } /** - * Test of getDirectReference method, of class - * org.owasp.esapi.AccessReferenceMap. - * - * @throws AccessControlException - * the access control exception - */ + * Test of getDirectReference method, of class + * org.owasp.esapi.AccessReferenceMap. + * + * @throws AccessControlException + * the access control exception + */ public void testGetDirectReference() throws AccessControlException { System.out.println("getDirectReference"); @@ -166,10 +166,10 @@ public void testGetDirectReference() throws AccessControlException { String dir = (String)instance.getDirectReference(ind); assertEquals(directReference, dir); try { - instance.getDirectReference("invalid"); - fail(); + instance.getDirectReference("invalid"); + fail(); } catch( AccessControlException e ) { - // success + // success } } @@ -192,8 +192,8 @@ public void testAddDirectReference() throws AccessControlException { String ind = instance.addDirectReference(directReference); String dir = (String)instance.getDirectReference(ind); assertEquals(directReference, dir); - String newInd = instance.addDirectReference(directReference); - assertEquals(ind, newInd); + String newInd = instance.addDirectReference(directReference); + assertEquals(ind, newInd); } /** @@ -214,8 +214,8 @@ public void testRemoveDirectReference() throws AccessControlException { assertNotNull(indirect); String deleted = instance.removeDirectReference(directReference); assertEquals(indirect,deleted); - deleted = instance.removeDirectReference("ridiculous"); - assertNull(deleted); + deleted = instance.removeDirectReference("ridiculous"); + assertNull(deleted); } diff --git a/src/test/java/org/owasp/esapi/reference/AuthenticatorTest.java b/src/test/java/org/owasp/esapi/reference/AuthenticatorTest.java index 7d62b6f9e..dcde90dc3 100644 --- a/src/test/java/org/owasp/esapi/reference/AuthenticatorTest.java +++ b/src/test/java/org/owasp/esapi/reference/AuthenticatorTest.java @@ -102,20 +102,20 @@ public void cleanup() { } } - - /** - * Test of createAccount method, of class org.owasp.esapi.Authenticator. - * - * @throws AuthenticationException + + /** + * Test of createAccount method, of class org.owasp.esapi.Authenticator. + * + * @throws AuthenticationException * the authentication exception * @throws EncryptionException - */ - @Test public void testCreateUser() throws AuthenticationException, EncryptionException { - System.out.println("createUser"); - String accountName = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS); - String password = instance.generateStrongPassword(); - User user = instance.createUser(accountName, password, password); - assertTrue(user.verifyPassword(password)); + */ + @Test public void testCreateUser() throws AuthenticationException, EncryptionException { + System.out.println("createUser"); + String accountName = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS); + String password = instance.generateStrongPassword(); + User user = instance.createUser(accountName, password, password); + assertTrue(user.verifyPassword(password)); try { instance.createUser(accountName, password, password); // duplicate user fail(); @@ -147,313 +147,313 @@ public void cleanup() { // success } try { - String uName = "ea234kEknr"; //sufficiently random password that also works as a username + String uName = "ea234kEknr"; //sufficiently random password that also works as a username instance.createUser(uName, uName, uName); // using username as password fail(); } catch (AuthenticationException e) { // success } - } + } - /** - * Test of generateStrongPassword method, of class - * org.owasp.esapi.Authenticator. - * - * @throws AuthenticationException - * the authentication exception - */ - @Test public void testGenerateStrongPassword() throws AuthenticationException { - System.out.println("generateStrongPassword"); - String oldPassword = "iiiiiiiiii"; // i is not allowed in passwords - this prevents failures from containing pieces of old password - String newPassword = null; - String username = "FictionalEsapiUser"; - User user = new DefaultUser(username); - for (int i = 0; i < 100; i++) { + /** + * Test of generateStrongPassword method, of class + * org.owasp.esapi.Authenticator. + * + * @throws AuthenticationException + * the authentication exception + */ + @Test public void testGenerateStrongPassword() throws AuthenticationException { + System.out.println("generateStrongPassword"); + String oldPassword = "iiiiiiiiii"; // i is not allowed in passwords - this prevents failures from containing pieces of old password + String newPassword = null; + String username = "FictionalEsapiUser"; + User user = new DefaultUser(username); + for (int i = 0; i < 100; i++) { try { newPassword = instance.generateStrongPassword(); instance.verifyPasswordStrength(oldPassword, newPassword, user); } catch( AuthenticationException e ) { - System.out.println( " FAILED >> " + newPassword + " : " + e.getLogMessage()); + System.out.println( " FAILED >> " + newPassword + " : " + e.getLogMessage()); fail(); } - } - try { - instance.verifyPasswordStrength("test56^$test", "abcdx56^$sl", user ); - } catch( AuthenticationException e ) { - // expected - } - } + } + try { + instance.verifyPasswordStrength("test56^$test", "abcdx56^$sl", user ); + } catch( AuthenticationException e ) { + // expected + } + } - /** - * Test of getCurrentUser method, of class org.owasp.esapi.Authenticator. - * + /** + * Test of getCurrentUser method, of class org.owasp.esapi.Authenticator. + * * * @throws Exception */ - @Test public void testGetCurrentUser() throws Exception { - System.out.println("getCurrentUser"); - String username1 = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS); - String username2 = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS); - User user1 = instance.createUser(username1, "getCurrentUser", "getCurrentUser"); - User user2 = instance.createUser(username2, "getCurrentUser", "getCurrentUser"); - user1.enable(); - MockHttpServletRequest request = new MockHttpServletRequest(); - MockHttpServletResponse response = new MockHttpServletResponse(); + @Test public void testGetCurrentUser() throws Exception { + System.out.println("getCurrentUser"); + String username1 = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS); + String username2 = ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS); + User user1 = instance.createUser(username1, "getCurrentUser", "getCurrentUser"); + User user2 = instance.createUser(username2, "getCurrentUser", "getCurrentUser"); + user1.enable(); + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); ESAPI.httpUtilities().setCurrentHTTP(request, response); - user1.loginWithPassword("getCurrentUser"); - User currentUser = instance.getCurrentUser(); - assertEquals( currentUser, user1 ); - instance.setCurrentUser( user2 ); - assertFalse( currentUser.getAccountName().equals( user2.getAccountName() ) ); - - Runnable echo = new Runnable() { - public void run() { - User a = null; - try { - String password = instance.generateStrongPassword(); - //Create account name using random strings to guarantee uniqueness among running threads. + user1.loginWithPassword("getCurrentUser"); + User currentUser = instance.getCurrentUser(); + assertEquals( currentUser, user1 ); + instance.setCurrentUser( user2 ); + assertFalse( currentUser.getAccountName().equals( user2.getAccountName() ) ); + + Runnable echo = new Runnable() { + public void run() { + User a = null; + try { + String password = instance.generateStrongPassword(); + //Create account name using random strings to guarantee uniqueness among running threads. String accountName=ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS); - a = instance.getUser(accountName); - if ( a != null ) { - instance.removeUser(accountName); - } - a = instance.createUser(accountName, password, password); - instance.setCurrentUser(a); - } catch (AuthenticationException e) { - //Use ErrorCollector to fail test. + a = instance.getUser(accountName); + if ( a != null ) { + instance.removeUser(accountName); + } + a = instance.createUser(accountName, password, password); + instance.setCurrentUser(a); + } catch (AuthenticationException e) { + //Use ErrorCollector to fail test. collector.addError(e); - } - User b = instance.getCurrentUser(); - collector.checkThat("Logged in user should equal original user", a.equals(b), new IsEqual(Boolean.TRUE)); - } - }; + } + User b = instance.getCurrentUser(); + collector.checkThat("Logged in user should equal original user", a.equals(b), new IsEqual(Boolean.TRUE)); + } + }; ThreadGroup tg = new ThreadGroup("test"); - for ( int i = 0; i<10; i++ ) { - new Thread( tg, echo ).start(); - } + for ( int i = 0; i<10; i++ ) { + new Thread( tg, echo ).start(); + } while (tg.activeCount() > 0 ) { Thread.sleep(100); } - } + } - /** - * Test of getUser method, of class org.owasp.esapi.Authenticator. - * - * @throws AuthenticationException - * the authentication exception - */ - @Test public void testGetUser() throws AuthenticationException { - System.out.println("getUser"); - String password = instance.generateStrongPassword(); - String accountName=ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS); - instance.createUser(accountName, password, password); - assertNotNull(instance.getUser( accountName )); - assertNull(instance.getUser( ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS) )); - } - + /** + * Test of getUser method, of class org.owasp.esapi.Authenticator. + * + * @throws AuthenticationException + * the authentication exception + */ + @Test public void testGetUser() throws AuthenticationException { + System.out.println("getUser"); + String password = instance.generateStrongPassword(); + String accountName=ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS); + instance.createUser(accountName, password, password); + assertNotNull(instance.getUser( accountName )); + assertNull(instance.getUser( ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS) )); + } + /** * * @throws org.owasp.esapi.errors.AuthenticationException */ @Test public void testGetUserFromRememberToken() throws AuthenticationException { - System.out.println("getUserFromRememberToken"); - String password = instance.generateStrongPassword(); - String accountName=ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS); - User user = instance.createUser(accountName, password, password); - user.enable(); - MockHttpServletRequest request = new MockHttpServletRequest(); - MockHttpServletResponse response = new MockHttpServletResponse(); - ESAPI.httpUtilities().setCurrentHTTP(request, response); - - System.out.println("getUserFromRememberToken - expecting failure"); - request.setCookie( HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME, "ridiculous" ); - try { - instance.login( request, response ); // wrong cookie will fail - fail(); - } catch( AuthenticationException e ) { - // expected - } + System.out.println("getUserFromRememberToken"); + String password = instance.generateStrongPassword(); + String accountName=ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS); + User user = instance.createUser(accountName, password, password); + user.enable(); + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + ESAPI.httpUtilities().setCurrentHTTP(request, response); + + System.out.println("getUserFromRememberToken - expecting failure"); + request.setCookie( HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME, "ridiculous" ); + try { + instance.login( request, response ); // wrong cookie will fail + fail(); + } catch( AuthenticationException e ) { + // expected + } - System.out.println("getUserFromRememberToken - expecting success"); - request = new MockHttpServletRequest(); - ESAPI.httpUtilities().setCurrentHTTP(request, response); - ESAPI.authenticator().setCurrentUser(user); - String newToken = ESAPI.httpUtilities().setRememberToken(request, response, password, 10000, "test.com", request.getContextPath() ); - request.setCookie( HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME, newToken ); + System.out.println("getUserFromRememberToken - expecting success"); + request = new MockHttpServletRequest(); + ESAPI.httpUtilities().setCurrentHTTP(request, response); + ESAPI.authenticator().setCurrentUser(user); + String newToken = ESAPI.httpUtilities().setRememberToken(request, response, password, 10000, "test.com", request.getContextPath() ); + request.setCookie( HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME, newToken ); user.logout(); // logout the current user so we can log them in with the remember cookie - User test2 = instance.login( request, response ); - assertSame( user, test2 ); - } - + User test2 = instance.login( request, response ); + assertSame( user, test2 ); + } + - - /** - * Test get user from session. - * - * @throws AuthenticationException - * the authentication exception - */ - @Test public void testGetUserFromSession() throws AuthenticationException { - System.out.println("getUserFromSession"); - assumeTrue(instance instanceof FileBasedAuthenticator); - String accountName=ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS); - String password = instance.generateStrongPassword(); - User user = instance.createUser(accountName, password, password); - user.enable(); - MockHttpServletRequest request = new MockHttpServletRequest(); - request.addParameter("username", accountName); - request.addParameter("password", password); - MockHttpServletResponse response = new MockHttpServletResponse(); - ESAPI.httpUtilities().setCurrentHTTP( request, response ); - instance.login( request, response); - User test = ((FileBasedAuthenticator)instance).getUserFromSession(); - assertEquals( user, test ); - } + + /** + * Test get user from session. + * + * @throws AuthenticationException + * the authentication exception + */ + @Test public void testGetUserFromSession() throws AuthenticationException { + System.out.println("getUserFromSession"); + assumeTrue(instance instanceof FileBasedAuthenticator); + String accountName=ESAPI.randomizer().getRandomString(8, EncoderConstants.CHAR_ALPHANUMERICS); + String password = instance.generateStrongPassword(); + User user = instance.createUser(accountName, password, password); + user.enable(); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addParameter("username", accountName); + request.addParameter("password", password); + MockHttpServletResponse response = new MockHttpServletResponse(); + ESAPI.httpUtilities().setCurrentHTTP( request, response ); + instance.login( request, response); + User test = ((FileBasedAuthenticator)instance).getUserFromSession(); + assertEquals( user, test ); + } - /** - * Test get user names. - * - * @throws AuthenticationException - * the authentication exception - */ - @Test public void testGetUserNames() throws AuthenticationException { - System.out.println("getUserNames"); - String password = instance.generateStrongPassword(); - String[] testnames = new String[10]; - for(int i=0;i allowedExecutables = secConf.getAllowedExecutables(); - - //is this really what should be returned? what about an empty list? - assertEquals(1, allowedExecutables.size()); - assertEquals("", allowedExecutables.get(0)); - - - Properties properties = new Properties(); - properties.setProperty(DefaultSecurityConfiguration.APPROVED_EXECUTABLES, String.valueOf("/bin/bzip2,/bin/diff, /bin/cvs")); - secConf = new DefaultSecurityConfiguration(properties); - allowedExecutables = secConf.getAllowedExecutables(); - assertEquals(3, allowedExecutables.size()); - assertEquals("/bin/bzip2", allowedExecutables.get(0)); - assertEquals("/bin/diff", allowedExecutables.get(1)); - - //this seems less than optimal, maybe each value should have a trim() done to it - //at least we know that this behavior exists, the property should'nt have spaces between values - assertEquals(" /bin/cvs", allowedExecutables.get(2)); - } - - @Test - public void testGetAllowedFileExtensions() { - - DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); - java.util.List allowedFileExtensions = secConf.getAllowedFileExtensions(); - assertFalse(allowedFileExtensions.isEmpty()); - - - Properties properties = new Properties(); - properties.setProperty(DefaultSecurityConfiguration.APPROVED_UPLOAD_EXTENSIONS, String.valueOf(".txt,.xml,.html,.png")); - secConf = new DefaultSecurityConfiguration(properties); - allowedFileExtensions = secConf.getAllowedFileExtensions(); - assertEquals(4, allowedFileExtensions.size()); - assertEquals(".html", allowedFileExtensions.get(2)); - } - - @Test - public void testGetAllowedFileUploadSize() { - DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); - //assert that the default is of some reasonable size - assertTrue(secConf.getAllowedFileUploadSize() > (1024 * 100)); - - final int expected = (1024 * 1000); - secConf = this.createWithProperty(DefaultSecurityConfiguration.MAX_UPLOAD_FILE_BYTES, String.valueOf(expected)); - assertEquals(expected, secConf.getAllowedFileUploadSize()); - } - - @Test - public void testGetParameterNames() { - //test the default - DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); - assertEquals("password", secConf.getPasswordParameterName()); - assertEquals("username", secConf.getUsernameParameterName()); - - Properties properties = new Properties(); - properties.setProperty(DefaultSecurityConfiguration.PASSWORD_PARAMETER_NAME, "j_password"); - properties.setProperty(DefaultSecurityConfiguration.USERNAME_PARAMETER_NAME, "j_username"); - secConf = new DefaultSecurityConfiguration(properties); - assertEquals("j_password", secConf.getPasswordParameterName()); - assertEquals("j_username", secConf.getUsernameParameterName()); - } - - @Test - public void testGetEncryptionAlgorithm() { - //test the default - DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); - assertEquals("AES", secConf.getEncryptionAlgorithm()); - - secConf = this.createWithProperty(DefaultSecurityConfiguration.ENCRYPTION_ALGORITHM, "3DES"); - assertEquals("3DES", secConf.getEncryptionAlgorithm()); - } - - @Test - public void testGetCipherXProperties() { - DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); - assertEquals("AES/CBC/PKCS5Padding", secConf.getCipherTransformation()); - //assertEquals("AES/CBC/PKCS5Padding", secConf.getC); - - Properties properties = new Properties(); - properties.setProperty(DefaultSecurityConfiguration.CIPHER_TRANSFORMATION_IMPLEMENTATION, "Blowfish/CFB/ISO10126Padding"); - secConf = new DefaultSecurityConfiguration(properties); - assertEquals("Blowfish/CFB/ISO10126Padding", secConf.getCipherTransformation()); - - secConf.setCipherTransformation("DESede/PCBC/PKCS5Padding"); - assertEquals("DESede/PCBC/PKCS5Padding", secConf.getCipherTransformation()); - - secConf.setCipherTransformation(null);//sets it back to default - assertEquals("Blowfish/CFB/ISO10126Padding", secConf.getCipherTransformation()); - } + private DefaultSecurityConfiguration createWithProperty(String key, String val) { + Properties properties = new Properties(); + properties.setProperty(key, val); + return new DefaultSecurityConfiguration(properties); + } + + @Test + public void testGetApplicationName() { + final String expected = "ESAPI_UnitTests"; + DefaultSecurityConfiguration secConf = this.createWithProperty(DefaultSecurityConfiguration.APPLICATION_NAME, expected); + assertEquals(expected, secConf.getApplicationName()); + } + + @Test + public void testGetLogImplementation() { + //test the default + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + assertEquals(DefaultSecurityConfiguration.DEFAULT_LOG_IMPLEMENTATION, secConf.getLogImplementation()); + + final String expected = "TestLogger"; + secConf = this.createWithProperty(DefaultSecurityConfiguration.LOG_IMPLEMENTATION, expected); + assertEquals(expected, secConf.getLogImplementation()); + } + + @Test + public void testAuthenticationImplementation() { + //test the default + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + assertEquals(DefaultSecurityConfiguration.DEFAULT_AUTHENTICATION_IMPLEMENTATION, secConf.getAuthenticationImplementation()); + + final String expected = "TestAuthentication"; + secConf = this.createWithProperty(DefaultSecurityConfiguration.AUTHENTICATION_IMPLEMENTATION, expected); + assertEquals(expected, secConf.getAuthenticationImplementation()); + } + + @Test + public void testEncoderImplementation() { + //test the default + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + assertEquals(DefaultSecurityConfiguration.DEFAULT_ENCODER_IMPLEMENTATION, secConf.getEncoderImplementation()); + + final String expected = "TestEncoder"; + secConf = this.createWithProperty(DefaultSecurityConfiguration.ENCODER_IMPLEMENTATION, expected); + assertEquals(expected, secConf.getEncoderImplementation()); + } + + @Test + public void testAccessControlImplementation() { + //test the default + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + assertEquals(DefaultSecurityConfiguration.DEFAULT_ACCESS_CONTROL_IMPLEMENTATION, secConf.getAccessControlImplementation()); + + final String expected = "TestAccessControl"; + secConf = this.createWithProperty(DefaultSecurityConfiguration.ACCESS_CONTROL_IMPLEMENTATION, expected); + assertEquals(expected, secConf.getAccessControlImplementation()); + } + + @Test + public void testEncryptionImplementation() { + //test the default + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + assertEquals(DefaultSecurityConfiguration.DEFAULT_ENCRYPTION_IMPLEMENTATION, secConf.getEncryptionImplementation()); + + final String expected = "TestEncryption"; + secConf = this.createWithProperty(DefaultSecurityConfiguration.ENCRYPTION_IMPLEMENTATION, expected); + assertEquals(expected, secConf.getEncryptionImplementation()); + } + + @Test + public void testIntrusionDetectionImplementation() { + //test the default + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + assertEquals(DefaultSecurityConfiguration.DEFAULT_INTRUSION_DETECTION_IMPLEMENTATION, secConf.getIntrusionDetectionImplementation()); + + final String expected = "TestIntrusionDetection"; + secConf = this.createWithProperty(DefaultSecurityConfiguration.INTRUSION_DETECTION_IMPLEMENTATION, expected); + assertEquals(expected, secConf.getIntrusionDetectionImplementation()); + } + + @Test + public void testRandomizerImplementation() { + //test the default + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + assertEquals(DefaultSecurityConfiguration.DEFAULT_RANDOMIZER_IMPLEMENTATION, secConf.getRandomizerImplementation()); + + final String expected = "TestRandomizer"; + secConf = this.createWithProperty(DefaultSecurityConfiguration.RANDOMIZER_IMPLEMENTATION, expected); + assertEquals(expected, secConf.getRandomizerImplementation()); + } + + @Test + public void testExecutorImplementation() { + //test the default + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + assertEquals(DefaultSecurityConfiguration.DEFAULT_EXECUTOR_IMPLEMENTATION, secConf.getExecutorImplementation()); + + final String expected = "TestExecutor"; + secConf = this.createWithProperty(DefaultSecurityConfiguration.EXECUTOR_IMPLEMENTATION, expected); + assertEquals(expected, secConf.getExecutorImplementation()); + } + + @Test + public void testHTTPUtilitiesImplementation() { + //test the default + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + assertEquals(DefaultSecurityConfiguration.DEFAULT_HTTP_UTILITIES_IMPLEMENTATION, secConf.getHTTPUtilitiesImplementation()); + + final String expected = "TestHTTPUtilities"; + secConf = this.createWithProperty(DefaultSecurityConfiguration.HTTP_UTILITIES_IMPLEMENTATION, expected); + assertEquals(expected, secConf.getHTTPUtilitiesImplementation()); + } + + @Test + public void testValidationImplementation() { + //test the default + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + assertEquals(DefaultSecurityConfiguration.DEFAULT_VALIDATOR_IMPLEMENTATION, secConf.getValidationImplementation()); + + final String expected = "TestValidation"; + secConf = this.createWithProperty(DefaultSecurityConfiguration.VALIDATOR_IMPLEMENTATION, expected); + assertEquals(expected, secConf.getValidationImplementation()); + } + + @Test + public void testGetEncryptionKeyLength() { + // test the default + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + assertEquals(128, secConf.getEncryptionKeyLength()); + + final int expected = 256; + secConf = this.createWithProperty(DefaultSecurityConfiguration.KEY_LENGTH, String.valueOf(expected)); + assertEquals(expected, secConf.getEncryptionKeyLength()); + } + + @Test + public void testGetKDFPseudoRandomFunction() { + // test the default + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + assertEquals("HmacSHA256", secConf.getKDFPseudoRandomFunction()); + + final String expected = "HmacSHA1"; + secConf = this.createWithProperty(DefaultSecurityConfiguration.KDF_PRF_ALG, expected); + assertEquals(expected, secConf.getKDFPseudoRandomFunction()); + } + + @Test + public void testGetMasterSalt() { + try { + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + secConf.getMasterSalt(); + fail("Expected Exception not thrown"); + } + catch (ConfigurationException ce) { + assertNotNull(ce.getMessage()); + } + + final String salt = "53081"; + final String property = ESAPI.encoder().encodeForBase64(salt.getBytes(), false); + Properties properties = new Properties(); + properties.setProperty(DefaultSecurityConfiguration.MASTER_SALT, property); + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(properties); + assertEquals(salt, new String(secConf.getMasterSalt())); + } + + @Test + public void testGetAllowedExecutables() { + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + java.util.List allowedExecutables = secConf.getAllowedExecutables(); + + //is this really what should be returned? what about an empty list? + assertEquals(1, allowedExecutables.size()); + assertEquals("", allowedExecutables.get(0)); + + + Properties properties = new Properties(); + properties.setProperty(DefaultSecurityConfiguration.APPROVED_EXECUTABLES, String.valueOf("/bin/bzip2,/bin/diff, /bin/cvs")); + secConf = new DefaultSecurityConfiguration(properties); + allowedExecutables = secConf.getAllowedExecutables(); + assertEquals(3, allowedExecutables.size()); + assertEquals("/bin/bzip2", allowedExecutables.get(0)); + assertEquals("/bin/diff", allowedExecutables.get(1)); + + //this seems less than optimal, maybe each value should have a trim() done to it + //at least we know that this behavior exists, the property should'nt have spaces between values + assertEquals(" /bin/cvs", allowedExecutables.get(2)); + } + + @Test + public void testGetAllowedFileExtensions() { + + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + java.util.List allowedFileExtensions = secConf.getAllowedFileExtensions(); + assertFalse(allowedFileExtensions.isEmpty()); + + + Properties properties = new Properties(); + properties.setProperty(DefaultSecurityConfiguration.APPROVED_UPLOAD_EXTENSIONS, String.valueOf(".txt,.xml,.html,.png")); + secConf = new DefaultSecurityConfiguration(properties); + allowedFileExtensions = secConf.getAllowedFileExtensions(); + assertEquals(4, allowedFileExtensions.size()); + assertEquals(".html", allowedFileExtensions.get(2)); + } + + @Test + public void testGetAllowedFileUploadSize() { + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + //assert that the default is of some reasonable size + assertTrue(secConf.getAllowedFileUploadSize() > (1024 * 100)); + + final int expected = (1024 * 1000); + secConf = this.createWithProperty(DefaultSecurityConfiguration.MAX_UPLOAD_FILE_BYTES, String.valueOf(expected)); + assertEquals(expected, secConf.getAllowedFileUploadSize()); + } + + @Test + public void testGetParameterNames() { + //test the default + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + assertEquals("password", secConf.getPasswordParameterName()); + assertEquals("username", secConf.getUsernameParameterName()); + + Properties properties = new Properties(); + properties.setProperty(DefaultSecurityConfiguration.PASSWORD_PARAMETER_NAME, "j_password"); + properties.setProperty(DefaultSecurityConfiguration.USERNAME_PARAMETER_NAME, "j_username"); + secConf = new DefaultSecurityConfiguration(properties); + assertEquals("j_password", secConf.getPasswordParameterName()); + assertEquals("j_username", secConf.getUsernameParameterName()); + } + + @Test + public void testGetEncryptionAlgorithm() { + //test the default + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + assertEquals("AES", secConf.getEncryptionAlgorithm()); + + secConf = this.createWithProperty(DefaultSecurityConfiguration.ENCRYPTION_ALGORITHM, "3DES"); + assertEquals("3DES", secConf.getEncryptionAlgorithm()); + } + + @Test + public void testGetCipherXProperties() { + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + assertEquals("AES/CBC/PKCS5Padding", secConf.getCipherTransformation()); + //assertEquals("AES/CBC/PKCS5Padding", secConf.getC); + + Properties properties = new Properties(); + properties.setProperty(DefaultSecurityConfiguration.CIPHER_TRANSFORMATION_IMPLEMENTATION, "Blowfish/CFB/ISO10126Padding"); + secConf = new DefaultSecurityConfiguration(properties); + assertEquals("Blowfish/CFB/ISO10126Padding", secConf.getCipherTransformation()); + + secConf.setCipherTransformation("DESede/PCBC/PKCS5Padding"); + assertEquals("DESede/PCBC/PKCS5Padding", secConf.getCipherTransformation()); + + secConf.setCipherTransformation(null);//sets it back to default + assertEquals("Blowfish/CFB/ISO10126Padding", secConf.getCipherTransformation()); + } - // NOTE: When SecurityConfiguration.getIVType() is finally removed, this test can be as well. - @Test - public void testIV() { - DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); - assertEquals("random", secConf.getIVType()); // Ensure that 'random' is the default type for getIVType(). + // NOTE: When SecurityConfiguration.getIVType() is finally removed, this test can be as well. + @Test + public void testIV() { + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + assertEquals("random", secConf.getIVType()); // Ensure that 'random' is the default type for getIVType(). Properties props = new Properties(); String ivType = null; props.setProperty(DefaultSecurityConfiguration.IV_TYPE, "fixed"); // No longer supported. secConf = new DefaultSecurityConfiguration( props ); - try { - ivType = secConf.getIVType(); // This should now throw a Configuration Exception. - fail("Expected ConfigurationException to be thrown for " + DefaultSecurityConfiguration.IV_TYPE + "=" + ivType); - } - catch (ConfigurationException ce) { - assertNotNull(ce.getMessage()); - } - - props.setProperty(DefaultSecurityConfiguration.IV_TYPE, "illegal"); // This will just result in a logSpecial message & "random" is returned. - secConf = new DefaultSecurityConfiguration(props); - ivType = secConf.getIVType(); - assertEquals(ivType, "random"); - } - - @Test - public void testGetAllowMultipleEncoding() { - DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); - assertFalse(secConf.getAllowMultipleEncoding()); - - secConf = this.createWithProperty(DefaultSecurityConfiguration.ALLOW_MULTIPLE_ENCODING, "yes"); - assertTrue(secConf.getAllowMultipleEncoding()); - - secConf = this.createWithProperty(DefaultSecurityConfiguration.ALLOW_MULTIPLE_ENCODING, "true"); - assertTrue(secConf.getAllowMultipleEncoding()); - - secConf = this.createWithProperty(DefaultSecurityConfiguration.ALLOW_MULTIPLE_ENCODING, "no"); - assertFalse(secConf.getAllowMultipleEncoding()); - } - - @Test - public void testGetDefaultCanonicalizationCodecs() { - DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); - assertFalse(secConf.getDefaultCanonicalizationCodecs().isEmpty()); - - String property = "org.owasp.esapi.codecs.TestCodec1,org.owasp.esapi.codecs.TestCodec2"; - secConf = this.createWithProperty(DefaultSecurityConfiguration.CANONICALIZATION_CODECS, property); - assertTrue(secConf.getDefaultCanonicalizationCodecs().contains("org.owasp.esapi.codecs.TestCodec1")); - } - - @Test - public void testGetDisableIntrusionDetection() { - DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); - assertFalse(secConf.getDisableIntrusionDetection()); - - secConf = this.createWithProperty(DefaultSecurityConfiguration.DISABLE_INTRUSION_DETECTION, "TRUE"); - assertTrue(secConf.getDisableIntrusionDetection()); - - secConf = this.createWithProperty(DefaultSecurityConfiguration.DISABLE_INTRUSION_DETECTION, "true"); - assertTrue(secConf.getDisableIntrusionDetection()); - - secConf = this.createWithProperty(DefaultSecurityConfiguration.DISABLE_INTRUSION_DETECTION, "false"); - assertFalse(secConf.getDisableIntrusionDetection()); - } - + try { + ivType = secConf.getIVType(); // This should now throw a Configuration Exception. + fail("Expected ConfigurationException to be thrown for " + DefaultSecurityConfiguration.IV_TYPE + "=" + ivType); + } + catch (ConfigurationException ce) { + assertNotNull(ce.getMessage()); + } + + props.setProperty(DefaultSecurityConfiguration.IV_TYPE, "illegal"); // This will just result in a logSpecial message & "random" is returned. + secConf = new DefaultSecurityConfiguration(props); + ivType = secConf.getIVType(); + assertEquals(ivType, "random"); + } + + @Test + public void testGetAllowMultipleEncoding() { + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + assertFalse(secConf.getAllowMultipleEncoding()); + + secConf = this.createWithProperty(DefaultSecurityConfiguration.ALLOW_MULTIPLE_ENCODING, "yes"); + assertTrue(secConf.getAllowMultipleEncoding()); + + secConf = this.createWithProperty(DefaultSecurityConfiguration.ALLOW_MULTIPLE_ENCODING, "true"); + assertTrue(secConf.getAllowMultipleEncoding()); + + secConf = this.createWithProperty(DefaultSecurityConfiguration.ALLOW_MULTIPLE_ENCODING, "no"); + assertFalse(secConf.getAllowMultipleEncoding()); + } + + @Test + public void testGetDefaultCanonicalizationCodecs() { + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + assertFalse(secConf.getDefaultCanonicalizationCodecs().isEmpty()); + + String property = "org.owasp.esapi.codecs.TestCodec1,org.owasp.esapi.codecs.TestCodec2"; + secConf = this.createWithProperty(DefaultSecurityConfiguration.CANONICALIZATION_CODECS, property); + assertTrue(secConf.getDefaultCanonicalizationCodecs().contains("org.owasp.esapi.codecs.TestCodec1")); + } + + @Test + public void testGetDisableIntrusionDetection() { + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration(new Properties()); + assertFalse(secConf.getDisableIntrusionDetection()); + + secConf = this.createWithProperty(DefaultSecurityConfiguration.DISABLE_INTRUSION_DETECTION, "TRUE"); + assertTrue(secConf.getDisableIntrusionDetection()); + + secConf = this.createWithProperty(DefaultSecurityConfiguration.DISABLE_INTRUSION_DETECTION, "true"); + assertTrue(secConf.getDisableIntrusionDetection()); + + secConf = this.createWithProperty(DefaultSecurityConfiguration.DISABLE_INTRUSION_DETECTION, "false"); + assertFalse(secConf.getDisableIntrusionDetection()); + } + @Test public void testNoSuchPropFile(){ try { @@ -358,11 +358,11 @@ public void testNoSuchPropFile(){ } - private String patternOrNull(Pattern p){ - return null==p?null:p.pattern(); - } + private String patternOrNull(Pattern p){ + return null==p?null:p.pattern(); + } - @Test + @Test public void testRootCPLoading(){ DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration("ESAPI-root-cp.properties"); assertEquals(patternOrNull(secConf.getValidationPattern("Test1")), "ValueFromFile1"); @@ -395,85 +395,85 @@ public void testRootCPLoadingAlt2(){ } @Test - public void testValidationsPropertiesFileOptions(){ - DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration("ESAPI-SingleValidatorFileChecker.properties"); - assertEquals(patternOrNull(secConf.getValidationPattern("Test1")), "ValueFromFile1"); - assertNull(secConf.getValidationPattern("Test2")); - assertNull(secConf.getValidationPattern("TestC")); - - secConf = new DefaultSecurityConfiguration("ESAPI-DualValidatorFileChecker.properties"); - assertEquals(patternOrNull(secConf.getValidationPattern("Test1")), "ValueFromFile1"); - assertEquals(patternOrNull(secConf.getValidationPattern("Test2")), "ValueFromFile2"); - assertNull(secConf.getValidationPattern("TestC")); + public void testValidationsPropertiesFileOptions(){ + DefaultSecurityConfiguration secConf = new DefaultSecurityConfiguration("ESAPI-SingleValidatorFileChecker.properties"); + assertEquals(patternOrNull(secConf.getValidationPattern("Test1")), "ValueFromFile1"); + assertNull(secConf.getValidationPattern("Test2")); + assertNull(secConf.getValidationPattern("TestC")); + + secConf = new DefaultSecurityConfiguration("ESAPI-DualValidatorFileChecker.properties"); + assertEquals(patternOrNull(secConf.getValidationPattern("Test1")), "ValueFromFile1"); + assertEquals(patternOrNull(secConf.getValidationPattern("Test2")), "ValueFromFile2"); + assertNull(secConf.getValidationPattern("TestC")); - secConf = new DefaultSecurityConfiguration("ESAPI-CommaValidatorFileChecker.properties"); - assertEquals(patternOrNull(secConf.getValidationPattern("TestC")), "ValueFromCommaFile"); - assertNull(secConf.getValidationPattern("Test1")); - assertNull(secConf.getValidationPattern("Test2")); + secConf = new DefaultSecurityConfiguration("ESAPI-CommaValidatorFileChecker.properties"); + assertEquals(patternOrNull(secConf.getValidationPattern("TestC")), "ValueFromCommaFile"); + assertNull(secConf.getValidationPattern("Test1")); + assertNull(secConf.getValidationPattern("Test2")); - secConf = new DefaultSecurityConfiguration("ESAPI-QuotedValidatorFileChecker.properties"); - assertEquals(patternOrNull(secConf.getValidationPattern("Test1")), "ValueFromFile1"); - assertEquals(patternOrNull(secConf.getValidationPattern("Test2")), "ValueFromFile2"); - assertEquals(patternOrNull(secConf.getValidationPattern("TestC")), "ValueFromCommaFile"); - } - - @Test - public void DefaultSearchPathTest(){ - assertEquals("", DefaultSearchPath.ROOT.value()); - assertEquals("resourceDirectory/", DefaultSearchPath.RESOURCE_DIRECTORY.value()); - assertEquals(".esapi/", DefaultSearchPath.DOT_ESAPI.value()); - assertEquals("esapi/", DefaultSearchPath.ESAPI.value()); - assertEquals("resources/", DefaultSearchPath.RESOURCES.value()); - assertEquals("src/main/resources/", DefaultSearchPath.SRC_MAIN_RESOURCES.value()); - } - - @Test - public void DefaultSearchPathEnumChanges(){ - int expected = 6; - int testValue = DefaultSearchPath.values().length; - assertEquals(expected, testValue); - } - - @Test - public void defaultPropertiesTest(){ - SecurityConfiguration sc = ESAPI.securityConfiguration(); -// # Maximum size of JSESSIONID for the application--the validator regex may have additional values. -// HttpUtilities.HTTPJSESSIONIDLENGTH=50 - assertEquals(50, sc.getIntProp("HttpUtilities.HTTPJSESSIONIDLENGTH")); -// # Maximum length of a URL (see https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers) -// HttpUtilities.URILENGTH=2000 - assertEquals(2000, sc.getIntProp("HttpUtilities.URILENGTH")); -// # Maximum length for an http scheme -// HttpUtilities.HTTPSCHEMELENGTH=10 - assertEquals(10, sc.getIntProp("HttpUtilities.HTTPSCHEMELENGTH")); -// # Maximum length for an http host -// HttpUtilities.HTTPHOSTLENGTH=100 - assertEquals(100, sc.getIntProp("HttpUtilities.HTTPHOSTLENGTH")); -// # Maximum length for an http path -// HttpUtilities.HTTPPATHLENGTH=150 - assertEquals(150, sc.getIntProp("HttpUtilities.HTTPPATHLENGTH")); -// #Maximum length for a context path -// HttpUtilities.contextPathLength=150 - assertEquals(150, sc.getIntProp("HttpUtilities.contextPathLength")); -// #Maximum length for an httpServletPath -// HttpUtilities.HTTPSERVLETPATHLENGTH=100 - assertEquals(100, sc.getIntProp("HttpUtilities.HTTPSERVLETPATHLENGTH")); -// #Maximum length for an http query parameter name -// HttpUtilities.httpQueryParamNameLength=100 - assertEquals(100, sc.getIntProp("HttpUtilities.httpQueryParamNameLength")); -// #Maximum length for an http query parameter -- old default was 2000, but that's the max length for a URL... -// HttpUtilities.httpQueryParamValueLength=500 - assertEquals(500, sc.getIntProp("HttpUtilities.httpQueryParamValueLength")); -// # Maximum size of HTTP header key--the validator regex may have additional values. -// HttpUtilities.MaxHeaderNameSize=256 - assertEquals(256, sc.getIntProp("HttpUtilities.MaxHeaderNameSize")); -// # Maximum size of HTTP header value--the validator regex may have additional values. -// HttpUtilities.MaxHeaderValueSize=4096 - assertEquals(4096, sc.getIntProp("HttpUtilities.MaxHeaderValueSize")); -// # Maximum length of a redirect -// HttpUtilities.maxRedirectLength=512 - assertEquals(512, sc.getIntProp("HttpUtilities.maxRedirectLength")); - } + secConf = new DefaultSecurityConfiguration("ESAPI-QuotedValidatorFileChecker.properties"); + assertEquals(patternOrNull(secConf.getValidationPattern("Test1")), "ValueFromFile1"); + assertEquals(patternOrNull(secConf.getValidationPattern("Test2")), "ValueFromFile2"); + assertEquals(patternOrNull(secConf.getValidationPattern("TestC")), "ValueFromCommaFile"); + } + + @Test + public void DefaultSearchPathTest(){ + assertEquals("", DefaultSearchPath.ROOT.value()); + assertEquals("resourceDirectory/", DefaultSearchPath.RESOURCE_DIRECTORY.value()); + assertEquals(".esapi/", DefaultSearchPath.DOT_ESAPI.value()); + assertEquals("esapi/", DefaultSearchPath.ESAPI.value()); + assertEquals("resources/", DefaultSearchPath.RESOURCES.value()); + assertEquals("src/main/resources/", DefaultSearchPath.SRC_MAIN_RESOURCES.value()); + } + + @Test + public void DefaultSearchPathEnumChanges(){ + int expected = 6; + int testValue = DefaultSearchPath.values().length; + assertEquals(expected, testValue); + } + + @Test + public void defaultPropertiesTest(){ + SecurityConfiguration sc = ESAPI.securityConfiguration(); +// # Maximum size of JSESSIONID for the application--the validator regex may have additional values. +// HttpUtilities.HTTPJSESSIONIDLENGTH=50 + assertEquals(50, sc.getIntProp("HttpUtilities.HTTPJSESSIONIDLENGTH")); +// # Maximum length of a URL (see https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers) +// HttpUtilities.URILENGTH=2000 + assertEquals(2000, sc.getIntProp("HttpUtilities.URILENGTH")); +// # Maximum length for an http scheme +// HttpUtilities.HTTPSCHEMELENGTH=10 + assertEquals(10, sc.getIntProp("HttpUtilities.HTTPSCHEMELENGTH")); +// # Maximum length for an http host +// HttpUtilities.HTTPHOSTLENGTH=100 + assertEquals(100, sc.getIntProp("HttpUtilities.HTTPHOSTLENGTH")); +// # Maximum length for an http path +// HttpUtilities.HTTPPATHLENGTH=150 + assertEquals(150, sc.getIntProp("HttpUtilities.HTTPPATHLENGTH")); +// #Maximum length for a context path +// HttpUtilities.contextPathLength=150 + assertEquals(150, sc.getIntProp("HttpUtilities.contextPathLength")); +// #Maximum length for an httpServletPath +// HttpUtilities.HTTPSERVLETPATHLENGTH=100 + assertEquals(100, sc.getIntProp("HttpUtilities.HTTPSERVLETPATHLENGTH")); +// #Maximum length for an http query parameter name +// HttpUtilities.httpQueryParamNameLength=100 + assertEquals(100, sc.getIntProp("HttpUtilities.httpQueryParamNameLength")); +// #Maximum length for an http query parameter -- old default was 2000, but that's the max length for a URL... +// HttpUtilities.httpQueryParamValueLength=500 + assertEquals(500, sc.getIntProp("HttpUtilities.httpQueryParamValueLength")); +// # Maximum size of HTTP header key--the validator regex may have additional values. +// HttpUtilities.MaxHeaderNameSize=256 + assertEquals(256, sc.getIntProp("HttpUtilities.MaxHeaderNameSize")); +// # Maximum size of HTTP header value--the validator regex may have additional values. +// HttpUtilities.MaxHeaderValueSize=4096 + assertEquals(4096, sc.getIntProp("HttpUtilities.MaxHeaderValueSize")); +// # Maximum length of a redirect +// HttpUtilities.maxRedirectLength=512 + assertEquals(512, sc.getIntProp("HttpUtilities.maxRedirectLength")); + } // Test some of the deprecated methods to make sure I didn't screw them up // given the double negatives on some these properties. diff --git a/src/test/java/org/owasp/esapi/reference/EncoderTest.java b/src/test/java/org/owasp/esapi/reference/EncoderTest.java index ed04b6d5b..c88737a7e 100644 --- a/src/test/java/org/owasp/esapi/reference/EncoderTest.java +++ b/src/test/java/org/owasp/esapi/reference/EncoderTest.java @@ -53,14 +53,14 @@ */ public class EncoderTest extends TestCase { - private static final String PREFERRED_ENCODING = "UTF-8"; - + private static final String PREFERRED_ENCODING = "UTF-8"; + /** - * Instantiates a new encoder test. - * - * @param testName - * the test name - */ + * Instantiates a new encoder test. + * + * @param testName + * the test name + */ public EncoderTest(String testName) { super(testName); } @@ -70,7 +70,7 @@ public EncoderTest(String testName) { * @throws Exception */ protected void setUp() throws Exception { - // none + // none } /** @@ -78,44 +78,44 @@ protected void setUp() throws Exception { * @throws Exception */ protected void tearDown() throws Exception { - // none + // none } /** - * Suite. - * - * @return the test - */ + * Suite. + * + * @return the test + */ public static Test suite() { TestSuite suite = new TestSuite(EncoderTest.class); return suite; } - /** - * Test of canonicalize method, of class org.owasp.esapi.Encoder. - * - * @throws EncodingException - */ - public void testCanonicalize() throws EncodingException { - System.out.println("canonicalize"); + /** + * Test of canonicalize method, of class org.owasp.esapi.Encoder. + * + * @throws EncodingException + */ + public void testCanonicalize() throws EncodingException { + System.out.println("canonicalize"); ArrayList list = new ArrayList(); list.add( "HTMLEntityCodec" ); - list.add( "PercentCodec" ); - Encoder instance = new DefaultEncoder( list ); - - // Test null paths - assertEquals( null, instance.canonicalize(null)); - assertEquals( null, instance.canonicalize(null, true)); - assertEquals( null, instance.canonicalize(null, false)); - assertEquals( null, instance.canonicalize(null, true, true)); - assertEquals( null, instance.canonicalize(null, true, false)); - assertEquals( null, instance.canonicalize(null, false, true)); - assertEquals( null, instance.canonicalize(null, false, false)); - - // test exception paths - assertEquals( "%", instance.canonicalize("%25", true)); - assertEquals( "%", instance.canonicalize("%25", false)); + list.add( "PercentCodec" ); + Encoder instance = new DefaultEncoder( list ); + + // Test null paths + assertEquals( null, instance.canonicalize(null)); + assertEquals( null, instance.canonicalize(null, true)); + assertEquals( null, instance.canonicalize(null, false)); + assertEquals( null, instance.canonicalize(null, true, true)); + assertEquals( null, instance.canonicalize(null, true, false)); + assertEquals( null, instance.canonicalize(null, false, true)); + assertEquals( null, instance.canonicalize(null, false, false)); + + // test exception paths + assertEquals( "%", instance.canonicalize("%25", true)); + assertEquals( "%", instance.canonicalize("%25", false)); assertEquals( "%", instance.canonicalize("%25")); assertEquals( "%F", instance.canonicalize("%25F")); @@ -261,9 +261,9 @@ public void testCanonicalize() throws EncodingException { assertEquals( "<", instance.canonicalize("\\003C")); assertEquals( "<", instance.canonicalize("\\0003C")); assertEquals( "<", instance.canonicalize("\\00003C")); - } + } - + /** * Test of canonicalize method, of class org.owasp.esapi.Encoder. * @@ -286,27 +286,27 @@ public void testDoubleEncodingCanonicalization() throws EncodingException { assertEquals( "<", instance.canonicalize("%26lt%3b", false)); //first entity, then percent assertEquals( "&", instance.canonicalize("%26", false)); //first percent, then entity - //enforce multiple and mixed encoding detection - try { - instance.canonicalize("%26lt; %26lt; %3c %3c %2526lt%253B %2526lt%253B %2526lt%253B", true, true); - fail("Multiple and mixed encoding not detected"); - } catch (IntrusionException ie) {} + //enforce multiple and mixed encoding detection + try { + instance.canonicalize("%26lt; %26lt; %3c %3c %2526lt%253B %2526lt%253B %2526lt%253B", true, true); + fail("Multiple and mixed encoding not detected"); + } catch (IntrusionException ie) {} - //enforce multiple but not mixed encoding detection - try { - instance.canonicalize("%252525253C", true, false); - fail("Multiple encoding not detected"); - } catch (IntrusionException ie) {} + //enforce multiple but not mixed encoding detection + try { + instance.canonicalize("%252525253C", true, false); + fail("Multiple encoding not detected"); + } catch (IntrusionException ie) {} - //enforce mixed but not multiple encoding detection - try { - instance.canonicalize("%25 %2526 %26#X3c;script> %3Cscript%25252525253e", false, true); - fail("Mixed encoding not detected"); - } catch (IntrusionException ie) {} + //enforce mixed but not multiple encoding detection + try { + instance.canonicalize("%25 %2526 %26#X3c;script> %3Cscript%25252525253e", false, true); + fail("Mixed encoding not detected"); + } catch (IntrusionException ie) {} - //enforce niether mixed nor multiple encoding detection -should canonicalize but not throw an error - assertEquals( "< < < < < < <", instance.canonicalize("%26lt; %26lt; %3c %3c %2526lt%253B %2526lt%253B %2526lt%253B", - false, false)); + //enforce niether mixed nor multiple encoding detection -should canonicalize but not throw an error + assertEquals( "< < < < < < <", instance.canonicalize("%26lt; %26lt; %3c %3c %2526lt%253B %2526lt%253B %2526lt%253B", + false, false)); // nested encoding examples assertEquals( "<", instance.canonicalize("%253c", false)); //nested encode % with percent @@ -344,7 +344,7 @@ public void testDoubleEncodingCanonicalization() throws EncodingException { } /** - * Test of encodeForHTML method, of class org.owasp.esapi.Encoder. + * Test of encodeForHTML method, of class org.owasp.esapi.Encoder. * * @throws Exception */ @@ -367,8 +367,8 @@ public void testEncodeForHTML() throws Exception { } /** - * Test of encodeForHTMLAttribute method, of class org.owasp.esapi.Encoder. - */ + * Test of encodeForHTMLAttribute method, of class org.owasp.esapi.Encoder. + */ public void testEncodeForHTMLAttribute() { System.out.println("encodeForHTMLAttribute"); Encoder instance = ESAPI.encoder(); @@ -395,31 +395,31 @@ public void testencodeForCSS() { } public void testCSSTripletLeadString() { - Encoder instance = ESAPI.encoder(); - assertEquals("rgb(255,255,255)\\21 ", instance.encodeForCSS("rgb(255,255,255)!")); - assertEquals("rgb(25%,25%,25%)\\21 ", instance.encodeForCSS("rgb(25%,25%,25%)!")); + Encoder instance = ESAPI.encoder(); + assertEquals("rgb(255,255,255)\\21 ", instance.encodeForCSS("rgb(255,255,255)!")); + assertEquals("rgb(25%,25%,25%)\\21 ", instance.encodeForCSS("rgb(25%,25%,25%)!")); } public void testCSSTripletTailString() { - Encoder instance = ESAPI.encoder(); - assertEquals("\\24 field\\3d rgb(255,255,255)\\21 ", instance.encodeForCSS("$field=rgb(255,255,255)!")); - assertEquals("\\24 field\\3d rgb(25%,25%,25%)\\21 ", instance.encodeForCSS("$field=rgb(25%,25%,25%)!")); + Encoder instance = ESAPI.encoder(); + assertEquals("\\24 field\\3d rgb(255,255,255)\\21 ", instance.encodeForCSS("$field=rgb(255,255,255)!")); + assertEquals("\\24 field\\3d rgb(25%,25%,25%)\\21 ", instance.encodeForCSS("$field=rgb(25%,25%,25%)!")); } public void testCSSTripletStringPart() { - Encoder instance = ESAPI.encoder(); - assertEquals("\\24 field\\3d rgb(255,255,255)\\21 ", instance.encodeForCSS("$field=rgb(255,255,255)!")); - assertEquals("\\24 field\\3d rgb(25%,25%,25%)\\21 ", instance.encodeForCSS("$field=rgb(25%,25%,25%)!")); + Encoder instance = ESAPI.encoder(); + assertEquals("\\24 field\\3d rgb(255,255,255)\\21 ", instance.encodeForCSS("$field=rgb(255,255,255)!")); + assertEquals("\\24 field\\3d rgb(25%,25%,25%)\\21 ", instance.encodeForCSS("$field=rgb(25%,25%,25%)!")); } public void testCSSTripletStringMultiPart() { - Encoder instance = ESAPI.encoder(); - assertEquals("\\24 field\\3d rgb(255,255,255)\\21 \\20 \\24 field\\3d rgb(255,255,255)\\21 ", instance.encodeForCSS("$field=rgb(255,255,255)! $field=rgb(255,255,255)!")); - assertEquals("\\24 field\\3d rgb(25%,25%,25%)\\21 \\20 \\24 field\\3d rgb(25%,25%,25%)\\21 ", instance.encodeForCSS("$field=rgb(25%,25%,25%)! $field=rgb(25%,25%,25%)!")); - assertEquals("\\24 field\\3d rgb(255,255,255)\\21 \\20 \\24 field\\3d rgb(25%,25%,25%)\\21 ", instance.encodeForCSS("$field=rgb(255,255,255)! $field=rgb(25%,25%,25%)!")); + Encoder instance = ESAPI.encoder(); + assertEquals("\\24 field\\3d rgb(255,255,255)\\21 \\20 \\24 field\\3d rgb(255,255,255)\\21 ", instance.encodeForCSS("$field=rgb(255,255,255)! $field=rgb(255,255,255)!")); + assertEquals("\\24 field\\3d rgb(25%,25%,25%)\\21 \\20 \\24 field\\3d rgb(25%,25%,25%)\\21 ", instance.encodeForCSS("$field=rgb(25%,25%,25%)! $field=rgb(25%,25%,25%)!")); + assertEquals("\\24 field\\3d rgb(255,255,255)\\21 \\20 \\24 field\\3d rgb(25%,25%,25%)\\21 ", instance.encodeForCSS("$field=rgb(255,255,255)! $field=rgb(25%,25%,25%)!")); } /** - * Test of encodeForJavaScript method, of class org.owasp.esapi.Encoder. - */ + * Test of encodeForJavaScript method, of class org.owasp.esapi.Encoder. + */ public void testEncodeForJavascript() { System.out.println("encodeForJavascript"); Encoder instance = ESAPI.encoder(); @@ -455,8 +455,8 @@ public void testEncodeForVBScript() { /** - * Test of encodeForXPath method, of class org.owasp.esapi.Encoder. - */ + * Test of encodeForXPath method, of class org.owasp.esapi.Encoder. + */ public void testEncodeForXPath() { System.out.println("encodeForXPath"); Encoder instance = ESAPI.encoder(); @@ -467,8 +467,8 @@ public void testEncodeForXPath() { /** - * Test of encodeForSQL method, of class org.owasp.esapi.Encoder. - */ + * Test of encodeForSQL method, of class org.owasp.esapi.Encoder. + */ public void testEncodeForSQL() { System.out.println("encodeForSQL"); Encoder instance = ESAPI.encoder(); @@ -495,8 +495,8 @@ public void testMySQLANSIModeQuoteInjection() { /** - * Test of encodeForLDAP method, of class org.owasp.esapi.Encoder. - */ + * Test of encodeForLDAP method, of class org.owasp.esapi.Encoder. + */ public void testEncodeForLDAP() { System.out.println("encodeForLDAP"); Encoder instance = ESAPI.encoder(); @@ -508,8 +508,8 @@ public void testEncodeForLDAP() { } /** - * Test of encodeForLDAP method with without encoding wildcard characters, of class org.owasp.esapi.Encoder. - */ + * Test of encodeForLDAP method with without encoding wildcard characters, of class org.owasp.esapi.Encoder. + */ public void testEncodeForLDAPWithoutEncodingWildcards() { System.out.println("encodeForLDAPWithoutEncodingWildcards"); Encoder instance = ESAPI.encoder(); @@ -520,8 +520,8 @@ public void testEncodeForLDAPWithoutEncodingWildcards() { } /** - * Test of encodeForDN method, of class org.owasp.esapi.Encoder. - */ + * Test of encodeForDN method, of class org.owasp.esapi.Encoder. + */ public void testEncodeForDN() { System.out.println("encodeForDN"); Encoder instance = ESAPI.encoder(); @@ -539,9 +539,9 @@ public void testEncodeForDN() { * Longstanding issue of always lowercasing named HTML entities. This will be set right now. */ public void testNamedUpperCaseDecoding(){ - String input = "Ü"; - String expected = "Ü"; - assertEquals(expected, ESAPI.encoder().decodeForHTML(input)); + String input = "Ü"; + String expected = "Ü"; + assertEquals(expected, ESAPI.encoder().decodeForHTML(input)); } public void testEncodeForXMLNull() { @@ -607,7 +607,7 @@ public void testEncodeForXMLAttributePound() { } /** - * Test of encodeForURL method, of class org.owasp.esapi.Encoder. + * Test of encodeForURL method, of class org.owasp.esapi.Encoder. * * @throws Exception */ @@ -619,7 +619,7 @@ public void testEncodeForURL() throws Exception { } /** - * Test of decodeFromURL method, of class org.owasp.esapi.Encoder. + * Test of decodeFromURL method, of class org.owasp.esapi.Encoder. * * @throws Exception */ @@ -627,29 +627,29 @@ public void testDecodeFromURL() throws Exception { System.out.println("decodeFromURL"); Encoder instance = ESAPI.encoder(); try { - assertEquals(null, instance.decodeFromURL(null)); + assertEquals(null, instance.decodeFromURL(null)); assertEquals(""; - assertTrue(instance.isValidSafeHTML("test9", input, 100, false, errors)); - String expected = "W<script>alert(1)</script>"; - String output = instance.getValidSafeHTML("escaping style tag attack with script tag", input, 250, false); - assertEquals(expected, output); - assertTrue(errors.size() == 0); + assertTrue(instance.isValidSafeHTML("test9", input, 100, false, errors)); + String expected = "W<script>alert(1)</script>"; + String output = instance.getValidSafeHTML("escaping style tag attack with script tag", input, 250, false); + assertEquals(expected, output); + assertTrue(errors.size() == 0); } @Test @@ -228,11 +228,11 @@ public void testOnfocusAfterStyleClosing() throws Exception { Validator instance = ESAPI.validator(); ValidationErrorList errors = new ValidationErrorList(); String input = "kinput/onfocus=alert(1)>"; - assertTrue(instance.isValidSafeHTML("test10", input, 100, false, errors)); - String expected = "k<input/onfocus=alert(1)>"; // Suspicious? Doesn't agree w/ AntiSamy test. - String output = instance.getValidSafeHTML("escaping style tag attack with onfocus attribute", input, 250, false); - assertEquals(expected, output); - assertTrue(errors.size() == 0); + assertTrue(instance.isValidSafeHTML("test10", input, 100, false, errors)); + String expected = "k<input/onfocus=alert(1)>"; // Suspicious? Doesn't agree w/ AntiSamy test. + String output = instance.getValidSafeHTML("escaping style tag attack with onfocus attribute", input, 250, false); + assertEquals(expected, output); + assertTrue(errors.size() == 0); } // This test was a DoS issue (CVE-2022-28366) within a transitive dependency (Neko-HtmlUnit) that AntiSamy uses. @@ -249,11 +249,11 @@ public void testNekoDOSWithAnHTMLComment() throws Exception { Validator instance = ESAPI.validator(); ValidationErrorList errors = new ValidationErrorList(); String input = " end", validationRule.getValid("", "beg