yacy_search_server/source/net/yacy/http/YaCyLegacyCredential.java
reger 0c754dd794 implemented DIGEST authentication, which is for remote login more secure
as BASIC were pwd is transmitted near clear text (B64enc).
This has some implication as RFC 2617 requires and recommends a password hash MD5(user:realm:pwd) for DIGEST.

!!! before activating DIGEST you have to reassign all passwords !!! to allow new calculation of the hash
- default authentication is still BASIC
- configuration at this time only manually in (DATA/settings) or  defaults/web.xml  (<auth-method>
- the realmname is in defaults/yacy.init  adminRealm=YaCy-AdminUI
- fyi: the realmname is shown on login screen
- changing the realm name invalidates all passwords - but for security you are encouraged to do so (as localhostadmin)
- implemented to support both, old hashes for BASIC and new hashes for BASIC and DIGEST
- to differentiate old / new hash the in Jetty used hash-prefix "MD5:" is used for new pwd-hashes (  "MD5:hash" )
2014-01-17 00:02:23 +01:00

132 lines
5.2 KiB
Java

//
// YaCyLegacyCredentials
// Copyright 2011 by Florian Richter
// First released 16.04.2011 at http://yacy.net
//
// $LastChangedDate$
// $LastChangedRevision$
// $LastChangedBy$
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program in the file lgpl21.txt
// If not, see <http://www.gnu.org/licenses/>.
//
package net.yacy.http;
import net.yacy.cora.order.Base64Order;
import net.yacy.cora.order.Digest;
import net.yacy.search.Switchboard;
import net.yacy.search.SwitchboardConstants;
import net.yacy.server.serverAccessTracker;
import org.eclipse.jetty.util.security.Credential;
/**
* implementation of YaCy's old admin password as jetty Credential
* supporting BASIC and DIGEST authentication
* and using MD5 encryptet passwords/credentials. Following RFC recommendation (to use the realm in MD5 hash)
* expecting a MD5 hash in format MD5( username:realm:password ), realm configured in yacy.init adminRealm
* (exception: old style credential MD5( username:password ) still accepted with BASIC auth)
*
*/
public class YaCyLegacyCredential extends Credential {
private static final long serialVersionUID = -3527894085562480001L;
private String hash; // remember password hash (for new style with prefix of used encryption supported "MD5:" )
private String foruser; // remember the user as YaCy credential is username:pwd (not just pwd)
private boolean isBase64enc; // remember hash encoding false = encodeMD5Hex(usr:pwd) ; true = encodeMD5Hex(Base64Order.standardCoder.encodeString(usr:pw))
private Credential c;
/**
* internal hash function for admin account
*
* @param pw clear password
* @return hash string
*/
public static String calcHash(String pw) { // old style hash
return Digest.encodeMD5Hex(Base64Order.standardCoder.encodeString(pw));
}
@Override
public boolean check(Object credentials) {
if (credentials instanceof Credential) { // for DIGEST auth
return ((Credential) credentials).check(c);
}
if (credentials instanceof String) { // for BASIC auth
final String pw = (String) credentials;
if (isBase64enc) {
if (serverAccessTracker.timeSinceAccessFromLocalhost() < 100) {
// we allow localhost accesses also to submit the hash as password
// this is very important since that method is used by the scripts in bin/ which are based on bin/apicall.sh
// the cleartext password is not stored anywhere, but we must find a way to allow scripts to steer a peer.
// this is the exception that makes that possible.
// TODO: it should be better to check the actual access IP here, but that is not handed over to Credential classes :(
if ((pw).equals(this.hash)) return true;
}
// exception for admin use old style MD5hash (user:password)
return calcHash(foruser + ":" + pw).equals(this.hash); // for admin user
}
// normal users (and new admin pwd)
if (hash.startsWith(MD5.__TYPE) && hash != null) {
return (Digest.encodeMD5Hex(foruser + ":" + Switchboard.getSwitchboard().getConfig(SwitchboardConstants.ADMIN_REALM,"YaCy")+":" + pw).equals(hash.substring(4)));
} else { // special check for old style password hash (prior v1.67/9501 15.1.2014)
return Digest.encodeMD5Hex(foruser + ":" + pw).equals(hash);
}
}
throw new UnsupportedOperationException();
}
/**
* create Credential object from config file hash
*
* @param configHash hash as in config file hash(adminuser:pwd)
* @return
*/
public static Credential getCredentialForAdmin(String username, String configHash) {
YaCyLegacyCredential yc = new YaCyLegacyCredential();
if (configHash.startsWith("MD5:")) {
yc.isBase64enc = false;
yc.c = Credential.getCredential(configHash);
} else {
yc.isBase64enc = true;
}
yc.foruser = username;
yc.hash = configHash;
return yc;
}
/**
* create Credential object from password
*
* @param username
* @param configHash encodeMD5Hex("user:realm:pwd") as stored in UserDB
* @return
*/
public static Credential getCredentialForUserDB(String username, String configHash) {
YaCyLegacyCredential yc = new YaCyLegacyCredential();
yc.c = Credential.getCredential(configHash); // creates a MD5 hash credential
yc.foruser = username;
yc.isBase64enc = false;
yc.hash = configHash;
return yc;
}
}