001    package com.nimbusds.jose.util;
002    
003    
004    import java.io.UnsupportedEncodingException;
005    
006    import org.apache.commons.codec.binary.Base64;
007    
008    import net.minidev.json.JSONAware;
009    import net.minidev.json.JSONValue;
010    
011    import net.jcip.annotations.Immutable;
012    
013    
014    /**
015     * Base64URL-encoded object.
016     *
017     * <p>Related specifications:
018     *
019     * <ul>
020     *     <li>RFC 4648.
021     * </ul>
022     *
023     * @author Vladimir Dzhuvinov
024     * @version $version$ (2013-01-15)
025     */
026    @Immutable
027    public class Base64URL implements JSONAware {
028    
029    
030            /**
031             * UTF-8 is the required charset for all JWTs.
032             */
033            private static final String CHARSET = "utf-8";
034            
035            
036            /**
037             * The Base64URL value.
038             */
039            private final String value;
040            
041            
042            /**
043             * Creates a new Base64URL-encoded object.
044             *
045             * @param base64URL The Base64URL-encoded object value. The value is not
046             *                  validated for having characters from a Base64URL 
047             *                  alphabet. Must not be {@code null}.
048             */
049            public Base64URL(final String base64URL) {
050            
051                    if (base64URL == null)
052                            throw new IllegalArgumentException("The Base64URL value must not be null");
053                    
054                    value = base64URL;
055            }
056            
057            
058            /**
059             * Decodes this Base64URL object to a byte array.
060             *
061             * @return The resulting byte array.
062             */
063            public byte[] decode() {
064            
065                    return Base64.decodeBase64(value);
066            }
067            
068            
069            /**
070             * Decodes this Base64URL object to a string.
071             *
072             * @return The resulting string, in the UTF-8 character set.
073             */
074            public String decodeToString() {
075            
076                    try {
077                            return new String(decode(), CHARSET);
078                            
079                    } catch (UnsupportedEncodingException e) {
080                    
081                            // UTF-8 should always be supported
082                            return "";
083                    }
084            }
085            
086            
087            /**
088             * Returns a JSON string representation of this object.
089             *
090             * @return The JSON string representation of this object.
091             */
092            public String toJSONString() {
093            
094                    return "\"" + JSONValue.escape(value) + "\"";
095            }
096            
097            
098            /**
099             * Returns a Base64URL string representation of this object.
100             *
101             * @return The Base64URL string representation.
102             */
103            public String toString() {
104            
105                    return value;
106            }
107            
108            
109            /**
110             * Overrides {@code Object.hashCode()}.
111             *
112             * @return The object hash code.
113             */
114            public int hashCode() {
115    
116                    return value.hashCode();
117            }
118    
119    
120            /**
121             * Overrides {@code Object.equals()}.
122             *
123             * @param object The object to compare to.
124             *
125             * @return {@code true} if the objects have the same value, otherwise
126             *         {@code false}.
127             */
128            public boolean equals(final Object object) {
129            
130                    return object != null && 
131                           object instanceof Base64URL && 
132                           this.toString().equals(object.toString());
133            }
134            
135            
136            /**
137             * Base64URL-encode the specified string.
138             *
139             * @param text The string to encode. Must be in the UTF-8 character set
140             *             and not {@code null}.
141             *
142             * @return The resulting Base64URL object.
143             */
144            public static Base64URL encode(final String text) {
145            
146                    try {
147                            return encode(text.getBytes(CHARSET));
148                            
149                    } catch (UnsupportedEncodingException e) {
150                    
151                            // UTF-8 should always be supported
152                            return null;
153                    }
154            }
155            
156            
157            /**
158             * Base64URL-encode the specified byte array.
159             *
160             * @param bytes The byte array to encode. Must not be {@code null}.
161             *
162             * @return The resulting Base64URL object.
163             */
164            public static Base64URL encode(final byte[] bytes) {
165            
166                    return new Base64URL(Base64.encodeBase64URLSafeString(bytes));
167            }
168    }