--- /dev/null
+package Lemonldap::NG::Portal::Password::My::KerberosAuth;
+
+use strict;
+use Mouse;
+use Expect;
+use Lemonldap::NG::Portal::Main::Constants qw(
+ PE_OK
+ PE_ERROR
+ PE_BADOLDPASSWORD
+ PE_PASSWORD_OK
+ PE_PASSWORD_MISMATCH
+ PE_PP_PASSWORD_TOO_SHORT
+ PE_PP_NOT_ALLOWED_CHARACTER
+ PE_PP_NOT_ALLOWED_CHARACTERS
+ PE_PP_MUST_SUPPLY_OLD_PASSWORD
+ PE_PP_INSUFFICIENT_PASSWORD_QUALITY
+ PE_PP_PASSWORD_IN_HISTORY
+);
+
+extends 'Lemonldap::NG::Portal::Password::Base';
+
+our $VERSION = '0.1.0';
+
+sub init {
+ my ($self) = @_;
+ return $self->SUPER::init;
+}
+
+sub confirm {
+ return 1;
+}
+
+sub modifyPassword {
+ my ( $self, $req, $pwd ) = @_;
+ my $kpasswd = "/usr/bin/kpasswd";
+
+ my $exp = new Expect;
+ $exp->raw_pty(1);
+
+ $exp->spawn($kpasswd, $req->{user});
+ my $r1 = $exp->expect(5, "Password for " . $req->{user});
+ unless( $r1 == 1 ){
+ $exp->hard_close();
+ $self->logger->error("kpasswd did not prompt for credentials for " . $req->{user});
+ return PE_ERROR;
+ }
+
+ $exp->send($req->data->{oldpassword} . "\n");
+ my @r2 = $exp->expect(5, "Enter new password: ", "Preauthentication failed getting initial ticket");
+ if( $r2[0] != 1 ){
+ $exp->hard_close();
+ if( $r2[0] == 2 ){
+ $self->logger->error("kpasswd failed for " . $req->{user} . ": incorrect old password" );
+ return PE_BADOLDPASSWORD;
+ } else {
+ $self->logger->error("kpasswd failed after prompt for old password for " . $req->{user} . ": " . join(' | ', @r2[0,2-4]) );
+ return PE_ERROR;
+ }
+ }
+ $exp->send($pwd . "\n");
+ my @r3 = $exp->expect(5, "Enter it again: ");
+ unless ( @r3[0] == 1 ){
+ $exp->hard_close();
+ $self->logger->error("kpasswd failed for " . $req->{user} . ": " . join(' | ', @r3[0,2-4]) );
+ # TODO: most appropriate error?
+ return PE_ERROR;
+ }
+ $exp->send($pwd . "\n");
+ my @r4 = $exp->expect(5, "Password changed", "Password change rejected: ");
+ unless( $r4[0] == 1 ){
+ $exp->hard_close();
+ $self->logger->error("kpasswd password change failed for " . $req->{user} . ": " . join(' | ', @r4[0,2-4]) );
+ if( $r4[4] =~ m{New password was used previously. Please choose a different password} ){
+ return PE_PP_PASSWORD_IN_HISTORY;
+ } else {
+ return PE_ERROR;
+ }
+ }
+
+ $exp->soft_close();
+ $self->logger->info("kpassword successful password change for " . $req->{user});
+
+ # if we get this far we've changed the password successfully
+ return PE_PASSWORD_OK;
+}
+
+# Override the checkPasswordQuality function from Password::Base because it has
+# a brain-dead 'special characters' policy.
+sub checkPasswordQuality {
+ my ( $self, $password ) = @_;
+
+ # Min size
+ if ( $self->conf->{passwordPolicyMinSize}
+ and length($password) < $self->conf->{passwordPolicyMinSize} )
+ {
+ $self->logger->error("Password too short");
+ return PE_PP_PASSWORD_TOO_SHORT;
+ }
+
+ # Min lower
+ if ( $self->conf->{passwordPolicyMinLower} ) {
+ my $lower = 0;
+ $lower++ while ( $password =~ m/\p{lowercase}/g );
+ if ( $lower < $self->conf->{passwordPolicyMinLower} ) {
+ $self->logger->error("Password has not enough lower characters");
+ return PE_PP_INSUFFICIENT_PASSWORD_QUALITY;
+ }
+ }
+
+ # Min upper
+ if ( $self->conf->{passwordPolicyMinUpper} ) {
+ my $upper = 0;
+ $upper++ while ( $password =~ m/\p{uppercase}/g );
+ if ( $upper < $self->conf->{passwordPolicyMinUpper} ) {
+ $self->logger->error("Password has not enough upper characters");
+ return PE_PP_INSUFFICIENT_PASSWORD_QUALITY;
+ }
+ }
+
+ # Min digit
+ if ( $self->conf->{passwordPolicyMinDigit} ) {
+ my $digit = 0;
+ $digit++ while ( $password =~ m/\d/g );
+ if ( $digit < $self->conf->{passwordPolicyMinDigit} ) {
+ $self->logger->error("Password has not enough digit characters");
+ return PE_PP_INSUFFICIENT_PASSWORD_QUALITY;
+ }
+ }
+
+ ## Special characters policy
+ my $speChars = $self->conf->{passwordPolicySpecialChar};
+ $speChars =~ s/\s+//g;
+
+ # Min special characters
+ if ( $self->conf->{passwordPolicyMinSpeChar} && $speChars ) {
+ my $spe = 0;
+ my $test = $password;
+ $spe = $test =~ s/[\Q$speChars\E]//g;
+ if ( $spe < $self->conf->{passwordPolicyMinSpeChar} ) {
+ $self->logger->error("Password has not enough special characters");
+ return PE_PP_INSUFFICIENT_PASSWORD_QUALITY;
+ }
+ }
+
+# # Fobidden special characters
+# $password =~ s/[\Q$speChars\E\w]//g;
+# if ($password) {
+# $self->logger->error( 'Password contains '
+# . length($password)
+# . " forbidden character(s): $password" );
+# return
+# length($password) > 1
+# ? PE_PP_NOT_ALLOWED_CHARACTERS
+# : PE_PP_NOT_ALLOWED_CHARACTER;
+# }
+
+ return PE_OK;
+}