001package org.apache.archiva.redback.policy.encoders; 002 003/* 004 * Copyright 2001-2006 The Apache Software Foundation. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019import org.apache.archiva.redback.policy.PasswordEncoder; 020import org.apache.archiva.redback.policy.PasswordEncodingException; 021import org.apache.archiva.redback.users.Messages; 022import org.apache.commons.codec.binary.Base64; 023import org.apache.commons.lang3.StringUtils; 024 025import java.nio.charset.Charset; 026import java.security.MessageDigest; 027import java.security.NoSuchAlgorithmException; 028 029/** 030 * Abstract Password Encoder that uses the {@link MessageDigest} from JAAS. 031 * 032 * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a> 033 */ 034public class AbstractJAASPasswordEncoder 035 implements PasswordEncoder 036{ 037 private String algorithm; 038 039 private Object systemSalt; 040 041 public AbstractJAASPasswordEncoder( String algorithm ) 042 { 043 this.algorithm = algorithm; 044 } 045 046 public void setSystemSalt( Object salt ) 047 { 048 this.systemSalt = salt; 049 } 050 051 public String encodePassword( String rawPass, Object salt ) 052 { 053 if ( rawPass == null ) 054 { 055 throw new IllegalArgumentException( "rawPass parameter cannot be null." ); 056 } 057 058 MessageDigest md = null; 059 try 060 { 061 md = MessageDigest.getInstance( this.algorithm ); 062 String precode = rawPass; 063 064 // Only checking for null, not using StringUtils.isNotEmpty() as 065 // whitespace can make up a valid salt. 066 if ( salt != null ) 067 { 068 // Conforming to acegi password encoding standards for compatibility 069 precode += "{" + salt + "}"; 070 } 071 md.update( precode.getBytes( Charset.forName( "UTF-8" ) ) ); 072 073 byte raw[] = md.digest(); 074 Base64 base64 = new Base64( 0, new byte[0] ); 075 return ( base64.encodeToString( raw ) ); 076 } 077 catch ( NoSuchAlgorithmException e ) 078 { 079 throw new PasswordEncodingException( 080 Messages.getString( "password.encoder.no.such.algoritm", this.algorithm ), e ); 081 } 082 } 083 084 public boolean isPasswordValid( String encPass, String rawPass, Object salt ) 085 { 086 if ( StringUtils.isEmpty( encPass ) ) 087 { 088 // TODO: Throw exception? 089 return false; 090 } 091 092 // PLXREDBACK-36 Commented out because a user with an empty password can't login due to the checking. 093 // Empty password checking can also be achieve by turning on MustHavePasswordRule. 094 //if ( StringUtils.isEmpty( rawPass ) ) 095 //{ 096 // TODO: Throw exception? 097 // return false; 098 //} 099 100 String testPass = encodePassword( rawPass, salt ); 101 return ( encPass.equals( testPass ) ); 102 } 103 104 public String encodePassword( String rawPass ) 105 { 106 return encodePassword( rawPass, this.systemSalt ); 107 } 108 109 public boolean isPasswordValid( String encPass, String rawPass ) 110 { 111 return isPasswordValid( encPass, rawPass, this.systemSalt ); 112 } 113 114}