/*
* Copyright (c) 2020. Virtualan Software Contributors (https://virtualan.io)
*
* 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 io.virtualan.csvson;
import io.virtualan.mapson.Mapson;
import io.virtualan.mapson.exception.BadInputDataException;
import java.util.AbstractMap;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.function.IntPredicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.json.JSONArray;
import org.json.JSONObject;
public class Csvson {
public static JSONArray buildCSVson(List<String> csvline) throws BadInputDataException {
String heading = csvline.get(0);
List<String> list = csvline.subList(1, csvline.size());
List<JSONObject> listJSONArray = list.stream().map(s -> {
try {
return new JSONObject(splitRow(heading, s));
} catch (BadInputDataException e) {
return null;
}
}).collect(Collectors.toList());
JSONArray array = new JSONArray();
listJSONArray.forEach(it -> array.put(it));
return array;
}
@FunctionalInterface
public interface SpecialFunction<T, R, E extends Exception> {
R apply(T t) throws E;
}
private <T, R, E extends Exception> Function<T, R> handle(SpecialFunction<T, R, E> fe) {
return arg -> {
try {
return fe.apply(arg);
} catch (Exception e) {
throw new RuntimeException("Missing element in the "+ arg);
}
};
}
private static String splitRow(String heading, String row) throws BadInputDataException {
String[] headings = heading.split(",");
String[] rows = row.split(",");
Map<String, String> rowMap =
IntStream.range(0, headings.length)
.mapToObj(i -> new AbstractMap.SimpleEntry<>(headings[i], rows[i]))
.collect(Collectors.toMap(k -> k.getKey(), v -> v.getValue()));
List<SimpleEntry<String, String>> mapsonList = rowMap.entrySet().stream()
.map(Csvson::buildKeyValuePairBase).flatMap(List::stream).collect(
Collectors.toList());
Map<String, String> mapson = mapsonList.stream()
.collect(LinkedHashMap::new, (m,v)->m.put(v.getKey(), v.getValue()), LinkedHashMap::putAll);
return Mapson.buildMAPsonAsJson(mapson);
}
private static List<SimpleEntry<String, String>> buildKeyValuePairBase(Entry<String, String> entry) {
String[] subElementParent = entry.getKey().split("/");
String prefix = subElementParent[0];
String[] subElement = indexExists(subElementParent, 1)? subElementParent[1].split(":") : null;
String[] subArrayElementValue = entry.getValue().split("\\|");
String[] subElementValue = entry.getValue().split(":");
Stream<List<SimpleEntry<String, String>>>
streamArrayElement = null;
if(subElement != null && subArrayElementValue != null ) {
if (subArrayElementValue.length > 1) {
streamArrayElement = IntStream.range(0, subArrayElementValue.length)
.mapToObj(i ->
getArrayElementList(prefix, subElement, subArrayElementValue[i].split(":"), i));
} else {
streamArrayElement = IntStream.range(0, 1)
.mapToObj(i ->
getElementList(prefix, subElement, subElementValue));
}
List subElementMap = streamArrayElement.flatMap(List::stream)
.collect(Collectors.toList());
System.out.println(subElementMap);
return subElementMap;
}
else {
if(subArrayElementValue != null && subArrayElementValue.length > 1) {
return IntStream.range(0, subArrayElementValue.length).mapToObj(i -> (new SimpleEntry<String, String>(prefix +"[" +i+"]",subArrayElementValue[i])))
.collect(Collectors.toList());
} else {
SimpleEntry<String, String> singleEntry = new SimpleEntry<String, String>(entry.getKey(),
entry.getValue());
List<SimpleEntry<String, String>> list = new ArrayList<>();
list.add(singleEntry);
return list;
}
}
}
private static List<SimpleEntry<String, String>> buildKeyValuePair(Entry<String, String> entry) {
String[] subElementParent = entry.getKey().split("/");
String prefix = subElementParent[0];
String[] subElement = subElementParent[1].split(":");
String[] subArrayElementValue = entry.getValue().split("\\|");
String[] subElementValue = entry.getValue().split(":");
Stream<List<SimpleEntry<String, String>>>
streamArrayElement = null;
if(subElement != null && subArrayElementValue != null ) {
if (subArrayElementValue.length > 1) {
streamArrayElement = IntStream.range(0, subArrayElementValue.length)
.mapToObj(i ->
getArrayElementList(prefix, subElement, subArrayElementValue[i].split(":"), i));
} else {
streamArrayElement = IntStream.range(0, 1)
.mapToObj(i ->
getElementList(prefix, subElement, subElementValue));
}
List subElementMap = streamArrayElement.flatMap(List::stream)
.collect(Collectors.toList());
System.out.println(subElementMap);
return subElementMap;
}
else {
if(subArrayElementValue != null) {
return IntStream.range(0, subArrayElementValue.length).mapToObj(i -> (new SimpleEntry<String, String>(prefix +"[" +i+"]",subArrayElementValue[i])))
.collect(Collectors.toList());
} else {
SimpleEntry<String, String> singleEntry = new SimpleEntry<String, String>(entry.getKey(),
entry.getValue());
List<SimpleEntry<String, String>> list = new ArrayList<>();
list.add(singleEntry);
return list;
}
}
}
private static List<SimpleEntry<String, String>> getElementList(String prefix, String[] subElement,
String[] valueElement) {
IntPredicate valueIsNotNull = i -> indexExists(valueElement, i) && valueElement[i] != null && !valueElement[i].equalsIgnoreCase("");
return IntStream.range(0, subElement.length)
.filter(valueIsNotNull).mapToObj(i -> (new SimpleEntry<String, String>(prefix +"." + subElement[i],
valueElement[i])))
.collect(Collectors.toList());
}
private static List<SimpleEntry<String, String>> getArrayElementList(String prefix, String[] subElement,
String[] valueElement, int index) {
IntPredicate valueIsNotNull = i -> indexExists(valueElement, i) && valueElement[i] != null && !valueElement[i].equalsIgnoreCase("");
return IntStream.range(0, subElement.length).filter(valueIsNotNull)
.mapToObj(i -> (new SimpleEntry<String, String>(prefix + "[" + index + "]." + subElement[i],
(indexExists(valueElement, i)) ? valueElement[i] : null)))
.collect(Collectors.toList());
}
private static boolean indexExists(String[] array,int index){
if(array!=null && index >= 0 && index < array.length)
return array[index] != null ? true : false;
else
return false;
}
}
My Learnings
Thursday, June 4, 2020
Csvson
Thursday, May 14, 2015
WS-Security Password Digest Policy implementation with CXF
Step 1: Add the following Password Digest policy xml snippet at the end of the service declaration in the WSDL
<wsp:policy wsu:id="CalcPlaintextPolicy">
<sp:supportingtokens>
<wsp:policy>
<sp:usernametoken sp:includetoken=
"http://docs.oasis-open.org/ws-sx/
ws-securitypolicy/200702/
IncludeToken/AlwaysToRecipient">
<wsp:policy>
<sp:hashpassword>
</sp:hashpassword></wsp:policy>
</sp:usernametoken>
</wsp:policy>
</sp:supportingtokens>
</wsp:policy>
Example:
<wsdl:service name="CalculatorService">
<wsdl:port binding="impl:CalculatorSoapBinding" name="Calculator">
<wsdlsoap:address location="http://localhost:8080/Calculator/services">
</wsdlsoap:address></wsdl:port>
</wsdl:service>
<!-- STARTS AFTER THE SERVICE -->
<wsp:policy wsu:id="CalcPlaintextPolicy">
<sp:supportingtokens>
<wsp:policy>
<sp:usernametoken sp:includetoken="
http://docs.oasis-open.org/ws-sx/
ws-securitypolicy/200702/IncludeToken/
AlwaysToRecipient">
<wsp:policy>
<!-- MAIN CHANGE ON THE WSDL IS -->
<sp:hashpassword>
</sp:hashpassword></wsp:policy>
</sp:usernametoken>
</wsp:policy>
</sp:supportingtokens>
</wsp:policy>
<!-- ENDS BEFORE THE WSDL DEFINITION -->
Step 2: Add the following policy reference snippet after the wsdl binding section of the WSDL
<wsp:policyreference uri="#CalcPlaintextPolicy"> </wsp:policyreference>
Example:
<wsdl:binding name="CalculatorSoapBinding" type="impl:Calculator">
<!--- START OF THE POLICY REFERENCE -->
<wsp:policyreference uri="#CalcPlaintextPolicy">
<wsdlsoap:binding transport="http://schemas.xmlsoap.org/soap/http">
<wsdl:operation name="add">
<wsdlsoap:operation soapaction="">
<wsdl:input name="addRequest">
<wsdlsoap:body use="literal">
</wsdlsoap:body></wsdl:input>
<wsdl:output name="addResponse">
<wsdlsoap:body use="literal">
</wsdlsoap:body></wsdl:output>
</wsdlsoap:operation></wsdl:operation>
<wsdl:operation name="sub">
<wsdlsoap:operation soapaction="">
<wsdl:input name="subRequest">
<wsdlsoap:body use="literal">
</wsdlsoap:body></wsdl:input>
<wsdl:output name="subResponse">
<wsdlsoap:body use="literal">
</wsdlsoap:body></wsdl:output>
</wsdlsoap:operation></wsdl:operation>
<wsdl:operation name="multi">
<wsdlsoap:operation soapaction="">
<wsdl:input name="multiRequest">
<wsdlsoap:body use="literal">
</wsdlsoap:body></wsdl:input>
<wsdl:output name="multiResponse">
<wsdlsoap:body use="literal">
</wsdlsoap:body></wsdl:output>
</wsdlsoap:operation></wsdl:operation>
<wsdl:operation name="div">
<wsdlsoap:operation soapaction="">
<wsdl:input name="divRequest">
<wsdlsoap:body use="literal">
</wsdlsoap:body></wsdl:input>
<wsdl:output name="divResponse">
<wsdlsoap:body use="literal">
</wsdlsoap:body></wsdl:output>
</wsdlsoap:operation></wsdl:operation>
</wsdlsoap:binding>
<!--- END OF THE POLICY REFERENCE -->
</wsp:policyreference>
</wsdl:binding>
Step 3: Use the below given snippet to configure the cxf-bean.xml.
Example:
<jaxws:endpoint address="/calculator" id="calculator" implementor="com.elan.calc.service.impl.CalculatorImpl">
<jaxws:features>
<bean class="org.apache.cxf.feature.LoggingFeature">
</bean></jaxws:features>
<jaxws:properties>
<entry key="ws-security.username" value="wsuser">
<entry key="ws-security.callback-handler" value-ref="wsSecPasswordCallback">
</entry></entry></jaxws:properties>
</jaxws:endpoint>
<bean class="com.elan.calc.ws.service.PasswordCallbackHandler" id="wsSecPasswordCallback">
</bean>
Refer the Example: callbackhandler
package com.elan.calc.ws.service;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;
public class PasswordCallbackHandler implements CallbackHandler {
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
System.out.println("identifier: " + pc.getIdentifier());
if (pc.getIdentifier().equals("wsuser")) {
// set the password on the callback. This will later be compared to // the // password which was sent from the client.
pc.setPassword("ws=USER");
}
}
}
WS Security namespaces used in the wsdl
xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsaws="http://www.w3.org/2005/08/addressing" xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702" xmlns:sp13="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200802" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
Wednesday, May 13, 2015
WS-Security Password PlainText/Digest Policy CXF Client Impl
This article will help to create WS -Security Client based CXF. It works for Plain password and Password Digest. User have to follow few steps to get one Jar created for the WS Client
Step 1: Create Java project and convert the project to maven based project. Copy your WSDL into the wsdl folder present in the project. provide wsdl path(even URL) in the cxf-codegen-plugin
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>2.1.2</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>${basedir}/src/</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/wsdl/CalculatorImpl.wsdl</wsdl>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
Write the client code like below and pass your callback and username for the WS Security
package com.elan.calc.service.impl;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import javax.xml.ws.BindingProvider;
import com.elan.calc.domain.Input;
public class WSClient {
public static void main(String[] args) throws MalformedURLException {
URL wsdlURL= new URL("http://localhost:8080/Calculator/services/calculator?wsdl");
CalculatorService service = new CalculatorService(wsdlURL);
Calculator port = service.getCalculator();
Map ctx = ((BindingProvider)port).getRequestContext();
ctx.put("ws-security.username", "wsuser");
ctx.put("ws-security.callback-handler", PasswordCallbackHandler.class.getName());
Input input = new Input();
input.setInputA(10);
input.setInputA(20);
int ret = port.add(input);
System.out.println(ret);
}
}
Callback Example:
package com.elan.calc.service.impl;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;
public class PasswordCallbackHandler implements CallbackHandler {
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
System.out.println("identifier: " + pc.getIdentifier());
if (pc.getIdentifier().equals("wsuser")) {
// set the password on the callback. This will later be compared to // the // password which was sent from the client.
pc.setPassword("ws=USER");
}
}
}
Example WS-security soap envelope Plain password
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:impl="http://impl.service.calc.elan.com"
xmlns:dom="http://domain.calc.elan.com">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/
wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>wsuser</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/
oasis-200401-wss-username-token-profile-1.0
#PasswordText">ws=USER</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<impl:add>
<impl:input>
<dom:inputA>5</dom:inputA>
<dom:inputB>5</dom:inputB>
</impl:input>
</impl:add>
</soapenv:Body>
</soapenv:Envelope>
Example WS-security soap envelope Password Digest
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Header> <wsse:Security soap:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="UsernameToken-B7CAA505B63AE99FD314316382790611"> <wsse:Username>wsuser</wsse:Username> <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">doAUEzig+QRcXp+04R/7zZx96oQ=</wsse:Password> <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">YNLZe1hq693qGsboH5dCag==</wsse:Nonce> <wsu:Created>2015-05-14T21:17:59.059Z</wsu:Created> </wsse:UsernameToken> </wsse:Security> </soap:Header> <soap:Body> <ns2:add xmlns="http://domain.calc.elan.com" xmlns:ns2="http://impl.service.calc.elan.com"> <ns2:input> <inputA>20</inputA> <inputB>14</inputB> </ns2:input> </ns2:add> </soap:Body> </soap:Envelope>
your ws security plain text/Digest Password policy Client implementation is completed successfully!!! You can also download complete working code from the following location. Thanks for visiting my learning blog.
Download Source CodeThursday, May 7, 2015
WS-Security PlainText Policy implementations with CXF
This article will help to learn WS-Security PlainText Policy implementation WSDL based approach. To implement 3 steps needs to be followed
Step 1: Add the following plain text policy xml snippet at the end of the service declaration in the WSDL
<wsp:policy wsu:id="CalcPlaintextPolicy">
<sp:supportingtokens>
<wsp:policy>
<sp:usernametoken sp:includetoken=
"http://docs.oasis-open.org/ws-sx/
ws-securitypolicy/200702/
IncludeToken/AlwaysToRecipient">
<wsp:policy>
</wsp:policy></sp:usernametoken>
</wsp:policy>
</sp:supportingtokens>
</wsp:policy>
Example:
<wsdl:service name="CalculatorService">
<wsdl:port binding="impl:CalculatorSoapBinding" name="Calculator">
<wsdlsoap:address location="http://localhost:8080/Calculator/services">
</wsdlsoap:address></wsdl:port>
</wsdl:service>
<!-- STARTS AFTER THE SERVICE -->
<wsp:policy wsu:id="CalcPlaintextPolicy">
<sp:supportingtokens>
<wsp:policy>
<sp:usernametoken sp:includetoken=
"http://docs.oasis-open.org/ws-sx/
ws-securitypolicy/200702/IncludeToken/
AlwaysToRecipient">
<wsp:policy>
</wsp:policy></sp:usernametoken>
</wsp:policy>
</sp:supportingtokens>
</wsp:policy>
<!-- ENDS BEFORE THE WSDL DEFINITION -->
</wsdl:definitions>
Step 2: Add the following plain text policy reference snippet after the wsdl binding section of the WSDL
<wsp:policyreference uri="#CalcPlaintextPolicy">
Example:
<wsdl:binding name="CalculatorSoapBinding" type="impl:Calculator">
<!--- START OF THE POLICY REFERENCE -->
<wsp:policyreference uri="#CalcPlaintextPolicy">
<wsdlsoap:binding transport="http://schemas.xmlsoap.org/soap/http">
<wsdl:operation name="add">
<wsdlsoap:operation soapaction="">
<wsdl:input name="addRequest">
<wsdlsoap:body use="literal">
</wsdlsoap:body></wsdl:input>
<wsdl:output name="addResponse">
<wsdlsoap:body use="literal">
</wsdlsoap:body></wsdl:output>
</wsdlsoap:operation></wsdl:operation>
<wsdl:operation name="sub">
<wsdlsoap:operation soapaction="">
<wsdl:input name="subRequest">
<wsdlsoap:body use="literal">
</wsdlsoap:body></wsdl:input>
<wsdl:output name="subResponse">
<wsdlsoap:body use="literal">
</wsdlsoap:body></wsdl:output>
</wsdlsoap:operation></wsdl:operation>
<wsdl:operation name="multi">
<wsdlsoap:operation soapaction="">
<wsdl:input name="multiRequest">
<wsdlsoap:body use="literal">
</wsdlsoap:body></wsdl:input>
<wsdl:output name="multiResponse">
<wsdlsoap:body use="literal">
</wsdlsoap:body></wsdl:output>
</wsdlsoap:operation></wsdl:operation>
<wsdl:operation name="div">
<wsdlsoap:operation soapaction="">
<wsdl:input name="divRequest">
<wsdlsoap:body use="literal">
</wsdlsoap:body></wsdl:input>
<wsdl:output name="divResponse">
<wsdlsoap:body use="literal">
</wsdlsoap:body></wsdl:output>
</wsdlsoap:operation></wsdl:operation>
</wsdlsoap:binding>
<!--- END OF THE POLICY REFERENCE -->
</wsp:policyreference>
</wsdl:binding>
Step 3: Use the below given snippet to configure the cxf-bean.xml.
Example:
<jaxws:endpoint address="/calculator" id="calculator"
implementor="com.elan.calc.service.impl.CalculatorImpl">
<jaxws:features>
<bean class="org.apache.cxf.feature.LoggingFeature">
</bean></jaxws:features>
<jaxws:properties>
<entry key="ws-security.username" value="wsuser">
<entry key="ws-security.callback-handler"
value-ref="wsSecPasswordCallback">
</entry></entry></jaxws:properties>
</jaxws:endpoint>
<bean class="com.elan.calc.ws.service.PasswordCallbackHandler"
id="wsSecPasswordCallback">
</bean>
Refer the Example: callbackhandler
package com.elan.calc.ws.service;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;
public class PasswordCallbackHandler implements CallbackHandler {
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
System.out.println("identifier: " + pc.getIdentifier());
if (pc.getIdentifier().equals("wsuser")) {
// set the password on the callback. This will later be compared to // the // password which was sent from the client.
pc.setPassword("ws=USER");
}
}
}
WS Security namespaces used in the wsdl
xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsaws="http://www.w3.org/2005/08/addressing" xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702" xmlns:sp13="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200802"
your ws security plain text policy implementation is completed successfully!!! You can also download complete working code from the following location. Thanks for visiting my learning blog.
Download Source CodeCsvson
/* * Copyright (c) 2020. Virtualan Software Contributors (https://virtualan.io) * * Licensed under the Apache License, Version 2.0 (...
-
This article will help to learn WS-Security Password Digest Policy implementation WSDL based approach. To implement 3 steps needs to b...