password validation with Kotlin

Viewed 1339

I'm new in Kotlin and trying to find the most elegant solution of password validation with conditions:

  1. Password must be at least 8 characters.
  2. It must have at least 1 lowercase and at least 1 uppercase letter.
  3. It must have one special character like ! or + or - or similar
  4. It must have at least 1 digit
2 Answers

"Elegant" is subjective!

Here's a functional approach to it:

// you can define each rule as a separate checking function,
// adding more doesn't change the complexity
fun String.isLongEnough() = length >= 8
fun String.hasEnoughDigits() = count(Char::isDigit) > 0
fun String.isMixedCase() = any(Char::isLowerCase) && any(Char::isUpperCase)
fun String.hasSpecialChar() = any { it in "!,+^" }

// you can decide which requirements need to be included (or make separate lists
// of different priority requirements, and check that enough of each have been met)
val requirements = listOf(String::isLongEnough, String::hasEnoughDigits)
val String.meetsRequirements get() = requirements.all { check -> check(this) }

fun main() {
    val password = "hiThere2!+"
    println(password.meetsRequirements)
}

I think the benefit is it's easy to add new rules and they can be very simple and readable, and you can handle the validation logic in a separate step (e.g. if you're implementing a "password strength" metric, where meeting some requirements counts more than others).

I've used some fancier language features in there, but it's to keep it concise really. The String.whatever() extension functions just mean you don't need to reference the string parameter in the function (it's this), and the function references (String::hasEnoughDigits) let you do that requirements.all call instead of going if (isLongEnough(password) && hasEnoughDigits(password) && ...) and so on. You could do it that way if you wanted!

Lots of options and ways to approach it. Regexes can definitely be elegant, but they can also be hard to work with

You can do like this ...

internal fun isValidPassword(password: String): Boolean {
        if (password.length < 8) return false
        if (password.filter { it.isDigit() }.firstOrNull() == null) return false
        if (password.filter { it.isLetter() }.filter { it.isUpperCase() }.firstOrNull() == null) return false
        if (password.filter { it.isLetter() }.filter { it.isLowerCase() }.firstOrNull() == null) return false
        if (password.filter { !it.isLetterOrDigit() }.firstOrNull() == null) return false

        return true
    }
Related