/* * Copyright 2016 Red Hat, Inc. and/or its affiliates * and other contributors as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.keycloak.saml.processing.web.util; import org.keycloak.saml.common.constants.GeneralConstants; import org.keycloak.saml.common.util.Base64; import org.keycloak.saml.common.util.StringUtil; import org.keycloak.saml.processing.api.util.DeflateUtil; import java.io.IOException; import java.io.InputStream; import java.net.URLDecoder; import java.net.URLEncoder; /** * Utility class for SAML HTTP/Redirect binding * * @author Anil.Saldhana@redhat.com * @since Jan 14, 2009 */ public class RedirectBindingUtil { /** * URL encode the string * * @param str * * @return * * @throws IOException */ public static String urlEncode(String str) throws IOException { return URLEncoder.encode(str, GeneralConstants.SAML_CHARSET_NAME); } /** * URL decode the string * * @param str * * @return * * @throws IOException */ public static String urlDecode(String str) throws IOException { return URLDecoder.decode(str, GeneralConstants.SAML_CHARSET_NAME); } /** * On the byte array, apply base64 encoding following by URL encoding * * @param stringToEncode * * @return * * @throws IOException */ public static String base64URLEncode(byte[] stringToEncode) throws IOException { String base64Request = Base64.encodeBytes(stringToEncode, Base64.DONT_BREAK_LINES); return urlEncode(base64Request); } /** * On the byte array, apply URL decoding followed by base64 decoding * * @param encodedString * * @return * * @throws IOException */ public static byte[] urlBase64Decode(String encodedString) throws IOException { String decodedString = urlDecode(encodedString); return Base64.decode(decodedString); } /** * Apply deflate compression followed by base64 encoding and URL encoding * * @param stringToEncode * * @return * * @throws IOException */ public static String deflateBase64URLEncode(String stringToEncode) throws IOException { return deflateBase64URLEncode(stringToEncode.getBytes(GeneralConstants.SAML_CHARSET)); } /** * Apply deflate compression followed by base64 encoding and URL encoding * * @param stringToEncode * * @return * * @throws IOException */ public static String deflateBase64URLEncode(byte[] stringToEncode) throws IOException { byte[] deflatedMsg = DeflateUtil.encode(stringToEncode); return base64URLEncode(deflatedMsg); } /** * Apply deflate compression followed by base64 encoding * * @param stringToEncode * * @return * * @throws IOException */ public static String deflateBase64Encode(byte[] stringToEncode) throws IOException { byte[] deflatedMsg = DeflateUtil.encode(stringToEncode); return Base64.encodeBytes(deflatedMsg); } /** * Apply URL decoding, followed by base64 decoding followed by deflate decompression * * @param encodedString * * @return * * @throws IOException */ public static InputStream urlBase64DeflateDecode(String encodedString) throws IOException { byte[] deflatedString = urlBase64Decode(encodedString); return DeflateUtil.decode(deflatedString); } /** * Base64 decode followed by Deflate decoding * * @param encodedString * * @return */ public static InputStream base64DeflateDecode(String encodedString) { byte[] base64decodedMsg = Base64.decode(encodedString); return DeflateUtil.decode(base64decodedMsg); } /** * Get the Query String for the destination url * * @param urlEncodedRequest * @param urlEncodedRelayState * @param sendRequest either going to be saml request or response * * @return */ public static String getDestinationQueryString(String urlEncodedRequest, String urlEncodedRelayState, boolean sendRequest) { StringBuilder sb = new StringBuilder(); if (sendRequest) sb.append("SAMLRequest=").append(urlEncodedRequest); else sb.append("SAMLResponse=").append(urlEncodedRequest); if (StringUtil.isNotNull(urlEncodedRelayState)) sb.append("&RelayState=").append(urlEncodedRelayState); return sb.toString(); } /** * Get the destination url * * @param holder * * @return * * @throws IOException */ public static String getDestinationURL(RedirectBindingUtilDestHolder holder) throws IOException { String destination = holder.destination; StringBuilder destinationURL = new StringBuilder(destination); if (destination.contains("?")) destinationURL.append("&"); else destinationURL.append("?"); destinationURL.append(holder.destinationQueryString); return destinationURL.toString(); } /** * A Destination holder that holds the destination host url and the destination query string */ public static class RedirectBindingUtilDestHolder { private String destination; private String destinationQueryString; public RedirectBindingUtilDestHolder setDestinationQueryString(String dest) { destinationQueryString = dest; return this; } public RedirectBindingUtilDestHolder setDestination(String dest) { destination = dest; return this; } } }