Wednesday, October 5, 2011

Securing Web Service Integration


Security is one of the key aspects of any software system. Authentication and Authorization are basic security requirement of any software system. In an SOA environment which most of the time is realized using web services, Username Token and HTTP basic authentication can be used to authenticate the users. Then XCMAL policy based authorization provides centralized authorization. Therefore this article describes such a SOA system written using WSO2 Enterprise Service Bus (ESB), further protecting the back end services using mutual authentication.
Date: Tue, 5th Jul, 2011
Level: Intermediate
Reads: 995 Comments: 3 | Login or register to post comments
Amila Suriarachchi

WSO2 Inc.
amila's picture

Introduction

There are different types of users in many corporate software systems. These different uses has different levels of access to the system and hence software systems should control the access according to the user. The access levels of users can be stored as policies in a file and the system should check against these polices when users making requests to different functionalities. This process is called Authorization in computer security. Before authorizing a user request, the software system should validate the user. In other words, it should be able to identify whether a request comes from a real user or an impersonate one. Typically user details are stored in a centralized location. Hence users are asked to provide some secret informations stored in the user store to verify the authenticity of the user. This process is called Authentication.In any SOA environment many web services are integrated to provide aggregated functionality. These aggregated web services should always authenticate the user, authorize the requests to the back end with the requested user and secure the communication with the back end services. Rest of this article describes how to develop such a secure system using WSO2 Carbon Platform products namely WSO2 ESBWSO2 Identity Server (IS) and WSO2 Business Rules Server (BRS).
In a previous article titled as Integrate rules with SOA, we saw how to use WSO2 ESB proxy service to integrate two rule services. But this integrated service is not secured. Both proxy service and back end rule services can be access by any user although out side users only need to access the proxy service which provides the integrated functionality.
The ScenarioWS-Security provides standard authentication techniques such as user name token, X509 signature based authentication and kerborse token based authentication. Out of these techniques user name token is the easiest way, hence we are going to use that technique for this article. In order to have the integrated functionality, users should have access to each and every back end services. The access control policies are written as a XCMAL policy. The policy enforcement is done by using the Entilement mediator which calls the Entilement Service runs inside the WSO2 IS. Entilement Service evaluates the request against the XCMAL policy stored in WSO2 IS server. Finally the access to the back end services are limited only to the ESB proxy service by using mutual Authentication. Full source code with the instructions to set up the system can be found fromhere.

Applies To

WSO2 IS3.2.0
WSO2 ESB4.0.0
WSO2 BRS1.2.0

Contents

Username Token to Authenticate users

Username Token (UT) which is defined under WS-Security specification, is composed of user name and password. When the UT is enabled to a service it expects client to send the UT as a soap header and service can authenticate the user using that information. WSO2 carbon supports UT even with HTTP basic authentication by converting the POX message received to a soap envelop. Security wizard which comes under the service dash board, can be used to to enable the UT for a particular service and the service is authenticated with the carbon user manager.

Client program

In order to invoke a service to which UT is engaged, client program has to send the soap envelope with the UT header. WSO2 carbon platform uses the Apache Rampart in order to invoke a secured service according to the security policy. The security policy file is used to specify the security requirements of the service. Following code is used to enable the security at the client program.
System.setProperty("javax.net.ssl.trustStore", "client/conf/wso2carbon.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "wso2carbon");

CustomerOrderServiceStub stub = new CustomerOrderServiceStub("https://localhost:8243/services/CustomerOrderService");

stub._getServiceClient().getOptions().setUserName("amila");

stub._getServiceClient().getOptions().setProperty(RampartMessageData.KEY_RAMPART_POLICY,
         PolicyEngine.getPolicy(new FileInputStream("client/conf/policy.xml")));

stub._getServiceClient().engageModule("rampart");
UT is send over HTTPS transport to secure the message. Therefore users need to specify a trust store which contains the server certificate (public key) with its password. Since this article uses same keystore as in the server by default it contains the server certificate. User name is given as an axis2 client option which is picked by the rampart. The password is picked from a call back handler which is given in the security policy. Following client program can be used to invoke the service with basic authentication.
System.setProperty("javax.net.ssl.trustStore", "client/conf/wso2carbon.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "wso2carbon");

CustomerOrderServiceStub stub = new CustomerOrderServiceStub("https://localhost:8243/services/CustomerOrderService");
HttpTransportProperties.Authenticator authenticator = new HttpTransportProperties.Authenticator();
authenticator.setUsername("amila");
authenticator.setPassword("chinthaka");

stub._getServiceClient().getOptions().setProperty(HTTPConstants.AUTHENTICATE, authenticator);
stub._getServiceClient().getOptions().setProperty(Constants.Configuration.ENABLE_REST, Constants.VALUE_TRUE);
First it creates an Authenticator object and set the user name and password to that. Axis2 commons HTTP transport uses this value to create the HTTP headers. Basic authentication based authentication for UT only works with the messages with content type application/xml. Therefore it is required to enable to REST to message.

XCMAL based policy to Authorize

The CustomerOrderService can be accessed by any authenticated user. But the two back end services namely PriceCalculatorService and OrderSelectorService can only be accessed by the users in priceCalculator and orderSelector roles respectively. In other words only users belongs to priceCalculator role is authorized for PriceCalculatorService and only users belongs to orderSelector role is authorized for OrderSelectorService. This authorization can be expressed using a XACML policy as follows.
<Policy xmlns="urn:oasis:names:tc:xacml:2.0:policy:schema:os"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      PolicyId="customerOrderPolicy"
      RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:deny-overrides">
    <Description> Policy Customer Order</Description>
    <Target/>
    <Rule RuleId="price_calculator_service_rule"
          Effect="Permit">
        <Target>
            <Subjects>
                <Subject>
                    <SubjectMatch
                          MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                        <AttributeValue
                              DataType="http://www.w3.org/2001/XMLSchema#string">priceCalculator</AttributeValue>
                        <SubjectAttributeDesignator
                              AttributeId="http://wso2.org/claims/role"
                              DataType="http://www.w3.org/2001/XMLSchema#string"/>
                    </SubjectMatch>
                </Subject>
            </Subjects>
            <Resources>
                <Resource>
                    <ResourceMatch
                          MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                        <AttributeValue
                              DataType="http://www.w3.org/2001/XMLSchema#string">https://localhost:9443/services/PriceCalculatorService</AttributeValue>
                        <ResourceAttributeDesignator
                              AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id"
                              DataType="http://www.w3.org/2001/XMLSchema#string"/>
                    </ResourceMatch>
                </Resource>
            </Resources>
            <Actions>
                <Action>
                    <ActionMatch
                          MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                        <AttributeValue
                              DataType="http://www.w3.org/2001/XMLSchema#string">invoke</AttributeValue>
                        <ActionAttributeDesignator
                              AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id"
                              DataType="http://www.w3.org/2001/XMLSchema#string"/>
                    </ActionMatch>
                </Action>
            </Actions>
        </Target>
    </Rule>
    <Rule RuleId="order_selector_service_rule"
          Effect="Permit">
        <Target>
            <Subjects>
                <Subject>
                    <SubjectMatch
                          MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                        <AttributeValue
                              DataType="http://www.w3.org/2001/XMLSchema#string">orderSelector</AttributeValue>
                        <SubjectAttributeDesignator
                              AttributeId="http://wso2.org/claims/role"
                              DataType="http://www.w3.org/2001/XMLSchema#string"/>
                    </SubjectMatch>
                </Subject>
            </Subjects>
            <Resources>
                <Resource>
                    <ResourceMatch
                          MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                        <AttributeValue
                              DataType="http://www.w3.org/2001/XMLSchema#string">https://localhost:9443/services/OrderSelectorService</AttributeValue>
                        <ResourceAttributeDesignator
                              AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id"
                              DataType="http://www.w3.org/2001/XMLSchema#string"/>
                    </ResourceMatch>
                </Resource>
            </Resources>
            <Actions>
                <Action>
                    <ActionMatch
                          MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                        <AttributeValue
                              DataType="http://www.w3.org/2001/XMLSchema#string">invoke</AttributeValue>
                        <ActionAttributeDesignator
                              AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id"
                              DataType="http://www.w3.org/2001/XMLSchema#string"/>
                    </ActionMatch>
                </Action>
            </Actions>
        </Target>
    </Rule>
</Policy>
As in any other authorization manager XCMAL uses subject, resource and action parameters to specify authorization policies. For this scenario it uses two rules to specify authorization policy. Since this is a web service action is always set to invoke.
This policy can be enforced within a proxy service using entitlement mediator. XACML policy is given in the WSO2 IS and the policy service can be accessed by any other server using Entitlement Service. Therefore location of this service, user name and password should be given in the entitlement mediator as follows.
<entitlementService remoteServiceUrl="https://localhost:9444/services" 
    remoteServiceUserName="admin" remoteServicePassword="admin" callbackClass="org.wso2.sample.CustomerOrderEntitlementCallback"/>
At runtime entitlement mediator sends the subject, resource and action details to the Entitlement service. The callbackClass can be used to give more specific details about these parameters. For this scenario we use the CustomerOrderEntitlementCallback class to send the user name obtain from the UT token, resource id given as a sequence property and set the action as invoke.
public class CustomerOrderEntitlementCallback extends UTEntitlementCallbackHandler {

    public String getUserName(MessageContext messageContext) {
        if (messageContext.getProperty("userName") == null) {
            String userName = super.getUserName(messageContext);
            messageContext.setProperty("userName", userName);
            return userName;
        } else {
            return (String) messageContext.getProperty("userName");
        }
    }

    public String findOperationName(MessageContext messageContext) {
        // we don't worry about the operation so return null
        return null;
    }

    public String findServiceName(MessageContext messageContext) {
        return (String) messageContext.getProperty("resourceID");
    }

    public String findAction(MessageContext messageContext) {
        return "invoke";
    }
}
Apache Rampart store the authenticated user in the message context as a property. However this property is only available in the out sequence path. For other paths it is required to save the user name with synapse context and reuse it.

Protecting Back end Services

Upto now we have secured the proxy service using a UT and the access to back end services through the proxy service. But if some one directly access the back end service there is no protection. These back end services can be secured using Mutual Authentication.
This technique can be used if the back end services are in a different server. Mutual Authentication requires clients to provide their certificate and authenticate with the back end service. For all WSO2 carbon platform products, it is possible to enable mutual authentication by setting the clientAuth parameter in the mgt-transports.xml. Once this parameter is set only a client with valid certificate can be accessed this service. However it is possible to directly access this service within the WSO2 ESB since WSO2 platform uses same keystore file in all products. In a practical situation it is required to import the back end server certificate to WSO2 ESB server key store and WSO2 ESB certificate to back end service keystore.

Conclusion

Security is one of the major concern of any software system. Web service integration is commonly used to form integrated functionality. In such an integrated web service can have a complex authorization logic depending on the services being integrated. Therefore this article describes how to implement such a authorization system using WSO2 ESB as the service integrator and WSO2 IS as the authorization manager. The authorization policy is written as a XACML policy file. Further it shows how users can be authenticated at the integrated service layer and how to secure the back end when running as a different server as well within the same server. It uses the UT in oder to authenticate the user and mutual authentication to secure the back end services.

Author

Amila Suriarachchi, Software Architect, WSO2 Inc.
AttachmentSize
sample.zip120.27 KB
dos.net.gmail.com's picture

ESB Sequence setting Error~

This is CustomerOrderInSequence :
<?xml version="1.0" encoding="UTF-8"?>
<sequence xmlns="http://ws.apache.org/ns/synapse" name="CustomerOrderInSequence" trace="enable" statistics="enable">
<property xmlns:ns="http://org.apache.synapse/xsd" xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" xmlns:ns3="http://org.apache.synapse/xsd" xmlns:ns5="http://wso2.org/sample/rule" xmlns:ns6="http://pojo.rule.sample/xsd" name="name" expression="//ns5:customerOrderRequest/ns5:Customer/ns6:name/text()" scope="default"/>
<xslt key="gov:/repository/paul/CustemerOrderInputTransfer.xslt"/>
<property name="nextSequence" value="OrderSelectorInSequence" scope="default" type="STRING"/>
<property name="resourceID" value="https://brs.cloud-test.104cloud.com.tw:9450/services/t/test.com/PriceCalculatorService/" scope="default" type="STRING"/>
<entitlementService remoteServiceUrl="https://identity.cloud-test.104cloud.com.tw:9444/services" remoteServiceUserName="admin" remoteServicePassword="admin" callbackClass="org.wso2.sample.CustomerOrderEntitlementCallback"/>
<send>
<endpoint>
<address uri="https://brs.cloud-test.104cloud.com.tw:9450/services/t/test.com/PriceCalculatorService/"/>
</endpoint>
</send>
<description/>
</sequence>
[wso2-esb-service.log]
2011-09-09 18:17:02,471 [-] [HttpServerWorker-10] WARN CustomerOrderService Exception encountered but no fault handler found - message dropped
[wso2-esb-trace.log]
18:18:45,322 [-] [HttpServerWorker-14] INFO TRACE_LOGGER End : Property mediator
18:19:02,490 [-] [HttpServerWorker-16] INFO TRACE_LOGGER Start : Sequence
18:19:02,490 [-] [HttpServerWorker-16] INFO TRACE_LOGGER Sequence :: mediate()
18:19:02,490 [-] [HttpServerWorker-16] INFO TRACE_LOGGER Start : Property mediator
18:19:02,491 [-] [HttpServerWorker-16] INFO TRACE_LOGGER Setting property : name at scope : default to : CustomerA (i.e. result of expression : //ns5:customerOrderRequest/ns5:Customer/ns6:name/text())
18:19:02,491 [-] [HttpServerWorker-16] INFO TRACE_LOGGER End : Property mediator
18:19:02,491 [-] [HttpServerWorker-16] INFO TRACE_LOGGER Start : XSLT mediator
18:19:02,493 [-] [HttpServerWorker-16] INFO TRACE_LOGGER output method: xml; encoding: UTF-8
18:19:02,493 [-] [HttpServerWorker-16] INFO TRACE_LOGGER Using org.apache.synapse.util.jaxp.StreamSourceBuilder
18:19:02,493 [-] [HttpServerWorker-16] INFO TRACE_LOGGER Using org.apache.synapse.util.jaxp.StreamResultBuilder
18:19:02,497 [-] [HttpServerWorker-16] INFO TRACE_LOGGER Transformation completed - processing result
18:19:02,498 [-] [HttpServerWorker-16] INFO TRACE_LOGGER Replace node with result
18:19:02,498 [-] [HttpServerWorker-16] INFO TRACE_LOGGER End : XSLT mediator
18:19:02,498 [-] [HttpServerWorker-16] INFO TRACE_LOGGER Start : Property mediator
18:19:02,498 [-] [HttpServerWorker-16] INFO TRACE_LOGGER Setting property : nextSequence at scope : default to : OrderSelectorInSequence (i.e. constant : OrderSelectorInSequence)
18:19:02,498 [-] [HttpServerWorker-16] INFO TRACE_LOGGER End : Property mediator
18:19:02,498 [-] [HttpServerWorker-16] INFO TRACE_LOGGER Start : Property mediator
18:19:02,498 [-] [HttpServerWorker-16] INFO TRACE_LOGGER Setting property : resourceID at scope : default to : https://brs.cloud-test.104cloud.com.tw:9450/services/t/test.com/PriceCalculatorService/ (i.e. constant : https://brs.cloud-test.104cloud.com.tw:9450/services/t/test.com/PriceCalculatorService/)
18:19:02,498 [-] [HttpServerWorker-16] INFO TRACE_LOGGER End : Property mediator
I got problem in
<entitlementService remoteServiceUrl="https://identity.cloud-test.104cloud.com.tw:9445/services" remoteServiceUserName="admin" remoteServicePassword="admin" callbackClass="org.wso2.sample.CustomerOrderEntitlementCallback"/>
It Can't work,why?
amila's picture

It seems like you use a

It seems like you use a tenant for normal message flow and use super tenant with IS. try a URL with https://identity.cloud-test.104cloud.com.tw:9445/a/test.com/services
dos.net.gmail.com's picture

I still got this Error~

I still got this Error~ why?
TID: [] [WSO2 Stratos Enterprise Service Bus] [2011-10-04 19:06:37,432] ERROR {org.wso2.carbon.identity.entitlement.mediator.EntitlementMediator} - userName:null {org.wso2.carbon.identity.entitlement.mediator.EntitlementMediator}
TID: [] [WSO2 Stratos Enterprise Service Bus] [2011-10-04 19:06:37,433] ERROR {org.wso2.carbon.identity.entitlement.mediator.EntitlementMediator} - serviceName:https://brs.cloud-test.104cloud.com.tw:9450/services/PriceCalculatorService {org.wso2.carbon.identity.entitlement.mediator.EntitlementMediator}
TID: [] [WSO2 Stratos Enterprise Service Bus] [2011-10-04 19:06:37,434] ERROR {org.wso2.carbon.identity.entitlement.mediator.EntitlementMediator} - operationName:null {org.wso2.carbon.identity.entitlement.mediator.EntitlementMediator}
TID: [] [WSO2 Stratos Enterprise Service Bus] [2011-10-04 19:06:37,435] ERROR {org.wso2.carbon.identity.entitlement.mediator.EntitlementMediator} - action:invoke {org.wso2.carbon.identity.entitlement.mediator.EntitlementMediator}
TID: [] [WSO2 Stratos Enterprise Service Bus] [2011-10-04 19:06:37,436] ERROR {org.wso2.carbon.identity.entitlement.mediator.EntitlementMediator} - env:null {org.wso2.carbon.identity.entitlement.mediator.EntitlementMediator}
TID: [] [WSO2 Stratos Enterprise Service Bus] [2011-10-04 19:06:37,437] ERROR {org.wso2.carbon.identity.entitlement.mediator.EntitlementMediator} - User name not provided for the Entitlement mediator - can't proceed {org.wso2.carbon.identity.entitlement.mediator.EntitlementMediator}
TID: [] [WSO2 Stratos Enterprise Service Bus] [2011-10-04 19:06:37,438] ERROR {org.wso2.carbon.identity.entitlement.mediator.EntitlementMediator} - Error occured while evaluating the policy {org.wso2.carbon.identity.entitlement.mediator.EntitlementMediator}
org.apache.synapse.SynapseException: User name not provided for the Entitlement mediator - can't proceed
at org.wso2.carbon.identity.entitlement.mediator.EntitlementMediator.mediate(EntitlementMediator.java:154)
at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:60)
at org.apache.synapse.mediators.base.SequenceMediator.mediate(SequenceMediator.java:114)
at org.apache.synapse.core.axis2.ProxyServiceMessageReceiver.receive(ProxyServiceMessageReceiver.java:144)
at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:181)
at org.apache.axis2.transport.http.HTTPTransportUtils.processHTTPPostRequest(HTTPTransportUtils.java:172)
at org.apache.synapse.transport.nhttp.ServerWorker.processEntityEnclosingMethod(ServerWorker.java:408)
at org.apache.synapse.transport.nhttp.ServerWorker.run(ServerWorker.java:259)
at org.apache.axis2.transport.base.threads.NativeWorkerPool$1.run(NativeWorkerPool.java:173)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)

2 comments:

  1. Консоли от компании Microsoft не сразу завоевали всемирную популярность и доверие игроков. Первая консоль под названием Xbox, вышедшая в далеком 2001 году, значительно уступала PlayStation 2 по количеству проданных приставок. Но все изменилось с выходом Xbox 360 - консоли седьмого поколения, которая стала по-настоящему "народной" для обитателей России и стран СНГ - Игры для Xbox 360 прошивка Kinect. Интернет-сайт Ru-Xbox.Ru является пользующимся популярностью ресурсом среди поклонников приставки, так как он предлагает игры для Xbox 360, которые поддерживают все существующие версии прошивок - совсем бесплатно! Зачем играть на оригинальном железе, если имеется эмуляторы? Для Xbox 360 игры выходили долгое время и находятся как посредственными проектами, так и хитами, многие из которых даже сегодня остаются уникальными для это консоли. Некоторые пользователи, желающие сыграть в игры для Xbox 360, могут задать вопрос: для чего необходимы игры для прошитых Xbox 360 freeboot или различными версиями LT, в случае если имеется эмулятор? Рабочий эмулятор Xbox 360 хоть и существует, но он требует производительного ПК, для покупки которого будет нужно вложить существенную сумму. К тому же, современные артефакты в виде исчезающих текстур, недостатка некоторых графических эффектов и освещения - могут изрядно попортить впечатления об игре и отбить желание для ее предстоящего прохождения. Что предлагает этот веб-сайт? Наш портал на сто процентов посвящен играм для приставки Xbox 360. У нас можно совершенно бесплатно и без регистрации загрузить игры на Xbox 360 через торрент для следующих версий прошивок консоли: - FreeBoot; - LT 3.0; - LT 2.0; - LT 1.9. Каждая прошивка имеет свои особенности обхода встроенной защиты. Поэтому, для запуска той либо иной игры потребуется загрузить специальную ее версию, которая стопроцентно приспособлена под одну из четырех вышеперечисленных прошивок. На нашем интернет-сайте вы можете без труда найти желаемый проект под нужную прошивку, так как возле каждой игры находится заглавие версии (FreeBoot, LT 3.0/2.0/1.9), под которую она приспособлена. Геймерам данного ресурса доступна особая категория игр для 360-го, предназначенных для Kinect - специального дополнения, которое считывает все движения одного либо нескольких игроков, и позволяет управлять с их помощью компьютерными персонажами. Большой выбор ПО Не считая способности скачать игры на Xbox 360 Freeboot либо LT различных версий, тут можно подобрать программное обеспечение для консоли от Майкрософт: - современные версии Dashboard, которые позволяют кастомизировать интерфейс консоли под свои нужды, сделав его более комфортным и современным; - браузеры; - просмотрщики файлов; - сохранения для игр; - темы для консоли; - программы, для конвертации образов и записи их на диск. Кроме вышеперечисленного игры на Xbox 360 Freeboot вы можете запускать не с дисковых, а с USB и многих других носителей, используя программу x360key, которую вы можете достать на нашем интернет-сайте. Посетителям доступно множество полезных статей, а также форум, где можно пообщаться с единомышленниками или попросить совета у более опытных хозяев консоли.

    ReplyDelete
  2. Your car could be stolen if you don't remember this!

    Consider that your car was taken! When you approach the police, they inquire about a specific "VIN search"

    Describe a VIN decoder.

    Similar to a passport, the "VIN decoder" allows you to find out the date of the car's birth and the identity of its "parent"( manufacturing plant). Additionally, you can find:

    1.Type of engine

    2.Automobile model

    3.The limitations of the DMV

    4.The number of drivers in this vehicle

    You will be able to locate the car, and keeping in mind the code ensures your safety. The code can be examined in the online database. The VIN is situated on various parts of the car to make it harder for thieves to steal, such as the first person sitting on the floor, the frame (often in trucks and SUVs), the spar, and other areas.

    What if the VIN is intentionally harmed?

    There are numerous circumstances that can result in VIN damage, but failing to have one will have unpleasant repercussions because it is illegal to intentionally harm a VIN in order to avoid going to jail or calling the police. You could receive a fine of up to 80,000 rubles and spend two years in prison. You might be held up on the road by a teacher.

    Conclusion.

    The VIN decoder may help to save your car from theft. But where can you check the car reality? This is why we exist– VIN decoders!

    ReplyDelete