001: /**
002: * Copyright (C) 2004-2007 Jive Software. All rights reserved.
003: *
004: * This software is published under the terms of the GNU Public License (GPL),
005: * a copy of which is included in this distribution.
006: */package org.jivesoftware.util;
007:
008: import static org.junit.Assert.*;
009:
010: import java.util.ArrayList;
011: import java.util.Collections;
012: import java.util.Iterator;
013: import java.util.List;
014:
015: import org.dom4j.Element;
016: import org.junit.Test;
017: import org.xmpp.packet.IQ;
018:
019: /**
020: * Test cases for the EntityCapabilitiesManager class.
021: *
022: * @author Armando Jagucki
023: */
024: public class EntityCapabilitiesManagerTest {
025:
026: @Test
027: public void testGenerateVerHash() {
028:
029: IQ iq = new IQ(IQ.Type.result);
030: iq.setFrom("nurse@capulet.lit/chamber");
031: iq.setTo("juliet@capulet.lit");
032: iq.setID("disco123");
033:
034: Element query = iq.setChildElement("query",
035: "http://jabber.org/protocol/disco#info");
036:
037: Element identity = query.addElement("identity");
038: identity.addAttribute("category", "client");
039: identity.addAttribute("type", "pc");
040:
041: Element feature = query.addElement("feature");
042: feature.addAttribute("var",
043: "http://jabber.org/protocol/disco#info");
044: feature = query.addElement("feature");
045: feature.addAttribute("var",
046: "http://jabber.org/protocol/disco#items");
047: feature = query.addElement("feature");
048: feature.addAttribute("var", "http://jabber.org/protocol/muc");
049:
050: assertEquals("Generating ver Hash #1",
051: "8RovUdtOmiAjzj+xI7SK5BCw3A8=", generateVerHash(iq));
052:
053: }
054:
055: @Test
056: public void testGenerateVerHash2() {
057: String S = "client/pc<http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<";
058: assertEquals("Generating ver Hash #2",
059: "8RovUdtOmiAjzj+xI7SK5BCw3A8=", StringUtils
060: .encodeBase64(StringUtils.decodeHex(StringUtils
061: .hash(S, "SHA-1"))));
062:
063: }
064:
065: @Test
066: public void testGenerateVerHash3() {
067: String S = "client/pda<http://jabber.org/protocol/geoloc<http://jabber.org/protocol/geoloc+notify<http://jabber.org/protocol/tune<http://jabber.org/protocol/tune+notify<";
068: assertEquals("Generating ver Hash #3",
069: "DqGwXvV/QC6X9QrPOFAwJoDwHkk=", StringUtils
070: .encodeBase64(StringUtils.decodeHex(StringUtils
071: .hash(S, "SHA-1"))));
072:
073: }
074:
075: @Test
076: public void testGenerateVerHash4() {
077: String S = "client/pc<http://jabber.org/protocol/activity<http://jabber.org/protocol/activity+notify<http://jabber.org/protocol/geoloc<http://jabber.org/protocol/geoloc+notify<http://jabber.org/protocol/muc<http://jabber.org/protocol/tune<http://jabber.org/protocol/tune+notify<";
078: assertEquals("Generating ver Hash #4",
079: "Hm1UHUVZowSehEBlWo8lO8mPy/M=", StringUtils
080: .encodeBase64(StringUtils.decodeHex(StringUtils
081: .hash(S, "SHA-1"))));
082:
083: }
084:
085: /**
086: * Generates a 'ver' hash attribute.
087: *
088: * In order to help prevent poisoning of entity capabilities information,
089: * the value of the 'ver' attribute is generated according to the method
090: * outlined in XEP-0115.
091: *
092: * @param packet
093: * @return the generated 'ver' hash
094: */
095: public String generateVerHash(IQ packet) {
096: // Initialize an empty string S.
097: String S = "";
098:
099: /*
100: * Sort the service discovery identities by category and then by type
101: * (if it exists), formatted as 'category' '/' 'type'.
102: */
103: List<String> discoIdentities = new ArrayList<String>();
104: Element query = packet.getChildElement();
105: Iterator identitiesIterator = query.elementIterator("identity");
106: if (identitiesIterator != null) {
107: while (identitiesIterator.hasNext()) {
108: Element identityElement = (Element) identitiesIterator
109: .next();
110:
111: String discoIdentity = identityElement
112: .attributeValue("category");
113: discoIdentity += '/';
114: discoIdentity += identityElement.attributeValue("type");
115:
116: discoIdentities.add(discoIdentity);
117: }
118: Collections.sort(discoIdentities);
119: }
120:
121: /*
122: * For each identity, append the 'category/type' to S, followed by the
123: * '<' character.
124: */
125: for (String discoIdentity : discoIdentities) {
126: S += discoIdentity;
127: S += '<';
128: }
129:
130: // Sort the supported features.
131: List<String> discoFeatures = new ArrayList<String>();
132: Iterator featuresIterator = query.elementIterator("feature");
133: if (featuresIterator != null) {
134: while (featuresIterator.hasNext()) {
135: Element featureElement = (Element) featuresIterator
136: .next();
137: String discoFeature = featureElement
138: .attributeValue("var");
139: discoFeatures.add(discoFeature);
140: }
141: Collections.sort(discoFeatures);
142: }
143:
144: /*
145: * For each feature, append the feature to S, followed by the '<'
146: * character.
147: */
148: for (String discoFeature : discoFeatures) {
149: S += discoFeature;
150: S += '<';
151: }
152:
153: /*
154: * Compute ver by hashing S using the SHA-1 algorithm as specified in
155: * RFC 3174 (with binary output) and encoding the hash using Base64 as
156: * specified in Section 4 of RFC 4648 (note: the Base64 output
157: * MUST NOT include whitespace and MUST set padding bits to zero).
158: */
159: S = StringUtils.hash(S, "SHA-1");
160: S = StringUtils.encodeBase64(StringUtils.decodeHex(S));
161:
162: return S;
163: }
164: }
|