// // (C) Copyright 2007 VeriSign, Inc. All Rights Reserved. // // VeriSign, Inc. shall have no responsibility, financial or // otherwise, for any consequences arising out of the use of // this material. The program material is provided on an "AS IS" // BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either // express or implied. // // Distributed under an Apache License // http://www.apache.org/licenses/LICENSE-2.0 // package org.verisign.joid; import java.math.BigInteger; import java.util.Iterator; import java.util.Map; import java.util.HashMap; import java.util.Set; import java.net.URLEncoder; import java.io.UnsupportedEncodingException; import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.Log; /** * Represents an OpenID association request. */ public class AssociationRequest extends Request { private final static Log log = LogFactory.getLog(AssociationRequest.class); private String sessionType; private String associationType; private BigInteger dhModulus; private BigInteger dhGenerator; private BigInteger dhConsumerPublic; private static String OPENID_SESSION_TYPE = "openid.session_type"; private static String OPENID_ASSOCIATION_TYPE = "openid.assoc_type"; private static String OPENID_DH_MODULUS = "openid.dh_modulus"; private static String OPENID_DH_GENERATOR = "openid.dh_gen"; private static String OPENID_DH_CONSUMER_PUBLIC = "openid.dh_consumer_public"; /** <code>no-encryption</code> as per the specification. */ public static String NO_ENCRYPTION = "no-encryption"; /** <code>DH-SHA256</code> as per the specification. */ public static String DH_SHA1 = "DH-SHA1"; /** <code>DH-SHA256</code> as per the specification. */ public static String DH_SHA256 = "DH-SHA256"; /** <code>HMAC-SHA1</code> as per the specification. */ public static String HMAC_SHA1 = "HMAC-SHA1"; /** <code>HMAC-SHA256</code> as per the specification. */ public static String HMAC_SHA256 = "HMAC-SHA256"; /** * Returns a ref to the static strings for subsequent * reference equality check (that is, no * <code>.equals()</code> needed) */ static String parseSessionType(String s) { if (NO_ENCRYPTION.equals(s)){ return NO_ENCRYPTION; } else if (DH_SHA1.equals(s)){ return DH_SHA1; } else if (DH_SHA256.equals(s)){ return DH_SHA256; } else { throw new IllegalArgumentException("Cannot parse session type: " +s); } } Map toMap() { Map map = super.toMap(); map.put(AssociationRequest.OPENID_SESSION_TYPE, sessionType); map.put(AssociationRequest.OPENID_ASSOCIATION_TYPE, associationType); map.put(AssociationRequest.OPENID_DH_CONSUMER_PUBLIC, Crypto.convertToString(dhConsumerPublic)); return map; } /** * Returns a ref to the static strings for subsequent * reference equality check (that is, no * <code>.equals()</code> needed) */ static String parseAssociationType(String s) { if (HMAC_SHA1.equals(s)){ return HMAC_SHA1; } else if (HMAC_SHA256.equals(s)){ return HMAC_SHA256; } else { throw new IllegalArgumentException("Cannot parse association type: "+s); } } private static BigInteger parseDhModulus(String s) { return Crypto.convertToBigIntegerFromString(s); } private static BigInteger parseDhGenerator(String s) { return Crypto.convertToBigIntegerFromString(s); } private static BigInteger parseDhConsumerPublic(String s) { return Crypto.convertToBigIntegerFromString(s); } /** * Creates a standard association request. Default values are * <code>HMAC-SHA1</code> for association type, and <code>DH-SHA1</code> * for session type. * * @param crypto the Crypto implementation to use. * @return an AssociationRequest. * @throws OpenIdException */ public static AssociationRequest create(Crypto crypto) { try { BigInteger pubKey = crypto.getPublicKey(); Map map = new HashMap(); map.put("openid.mode","associate"); map.put(OPENID_ASSOCIATION_TYPE, HMAC_SHA1); map.put(OPENID_SESSION_TYPE, DH_SHA1); map.put(OPENID_NS, OPENID_20_NAMESPACE); map.put(OPENID_DH_CONSUMER_PUBLIC, Crypto.convertToString(pubKey)); return new AssociationRequest(map, "associate"); } catch (OpenIdException e) { throw new IllegalArgumentException(e.toString()); } } AssociationRequest(Map map, String mode) throws OpenIdException { super(map, mode); this.sessionType = NO_ENCRYPTION; //default value this.associationType = HMAC_SHA1; //default value this.dhModulus = DiffieHellman.DEFAULT_MODULUS; this.dhGenerator = DiffieHellman.DEFAULT_GENERATOR; Set set = map.entrySet(); for (Iterator iter=set.iterator(); iter.hasNext();){ Map.Entry mapEntry = (Map.Entry) iter.next(); String key = (String) mapEntry.getKey(); String value = (String) mapEntry.getValue(); if (OPENID_SESSION_TYPE.equals(key)){ this.sessionType = AssociationRequest.parseSessionType(value); } else if (OPENID_ASSOCIATION_TYPE.equals(key)){ this.associationType = AssociationRequest.parseAssociationType(value); } else if (OPENID_DH_MODULUS.equals(key)){ this.dhModulus = AssociationRequest.parseDhModulus(value); } else if (OPENID_DH_GENERATOR.equals(key)){ this.dhGenerator = AssociationRequest.parseDhGenerator(value); } else if (OPENID_DH_CONSUMER_PUBLIC.equals(key)){ this.dhConsumerPublic = AssociationRequest.parseDhConsumerPublic(value); } } checkInvariants(); } /** * Returns whether the session type in use is not encrypted. * * @return whether the session type is not encrypted. */ public boolean isNotEncrypted() { return (AssociationRequest.NO_ENCRYPTION.equals(sessionType)); } private void checkInvariants() throws OpenIdException { if (mode == null){ throw new OpenIdException("Missing mode"); } if (associationType == null){ throw new OpenIdException("Missing association type"); } if (sessionType == null){ throw new OpenIdException("Missing session type"); } if (((sessionType.equals(AssociationRequest.DH_SHA1)) && (!associationType.equals(AssociationRequest.HMAC_SHA1))) || ((sessionType.equals(AssociationRequest.DH_SHA256)) && (!associationType.equals(AssociationRequest.HMAC_SHA256)))) { throw new OpenIdException("Mismatch "+OPENID_SESSION_TYPE +" and "+OPENID_ASSOCIATION_TYPE); } if ((sessionType.equals(AssociationRequest.DH_SHA1)) || (sessionType.equals(AssociationRequest.DH_SHA256))){ if (dhConsumerPublic == null){ throw new OpenIdException("Missing " +OPENID_DH_CONSUMER_PUBLIC); } } } public Response processUsing(ServerInfo si) throws OpenIdException { Store store = si.getStore(); Crypto crypto = si.getCrypto(); Association a = store.generateAssociation(this, crypto); store.saveAssociation(a); return new AssociationResponse(this, a, crypto); } /** * Returns the DH modulus. * * @return the DH modulus. */ public BigInteger getDhModulus(){return this.dhModulus;} /** * Returns the DH generator. * * @return the DH generator. */ public BigInteger getDhGenerator(){return this.dhGenerator;} /** * Returns the DH public value. * * @return the DH public value. */ public BigInteger getDhConsumerPublic(){return this.dhConsumerPublic;} /** * Returns the association session type. * * @return the association session type. */ public String getSessionType(){return this.sessionType;} /** * Returns the association type of this request. * * @return the association type. */ public String getAssociationType(){return this.associationType;} public String toString() { return "[AssociationRequest " + super.toString() +", session type="+sessionType +", association type="+associationType +"]"; } }