Securing REST API with WSO2 IS and XACML Policy - oauth-2.0

I try to secure my rest API(in wso2 ESB) with OAuth mediator and wso2 IS.
I want to permit a user with a valid token, when, the request is matching a specific URI (that call from ESB exp /sample/test) and also matches with other conditions such as scope_name and client_ip.
I can check username, scope_name in XACML policy and permit it but I want to add client_id and specific URI!
This is my sample Rest API in WSO2 ESB:
<api xmlns="http://ws.apache.org/ns/synapse" name="sample" context="/sample">
<resource methods="GET" uri-template="/test">
<inSequence>
<log level="custom">
<property name="ip address" expression="get-property('axis2','REMOTE_ADDR')"/>
</log>
<oauthService remoteServiceUrl="https://localhost:9444/services/" username="admin" password="admin"/>
<payloadFactory media-type="json">
<format>{"result":true}</format>
<args/>
</payloadFactory>
<respond/>
</inSequence>
</resource>
</api>
in WSO2 IS I create a service provider with below config:
<?xml version="1.0" encoding="UTF-8"?><ServiceProvider>
<ApplicationName>samplesp</ApplicationName>
<Description/>
<InboundAuthenticationConfig>
<InboundAuthenticationRequestConfigs>
<InboundAuthenticationRequestConfig>
<InboundAuthKey>samplesp</InboundAuthKey>
<InboundAuthType>passivests</InboundAuthType>
<InboundConfigType>standardAPP</InboundConfigType>
<Properties/>
</InboundAuthenticationRequestConfig>
<InboundAuthenticationRequestConfig>
<InboundAuthKey>U_SCMKqXqfJqSvyoD5LKFQ3Or7ka</InboundAuthKey>
<InboundAuthType>oauth2</InboundAuthType>
<InboundConfigType>standardAPP</InboundConfigType>
<inboundConfiguration><![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<oAuthAppDO>
<oauthConsumerKey>U_SCMKqXqfJqSvyoD5LKFQ3Or7ka</oauthConsumerKey>
<applicationName>samplesp</applicationName>
<callbackUrl></callbackUrl>
<oauthVersion>OAuth-2.0</oauthVersion>
<grantTypes>refresh_token password client_credentials </grantTypes>
<scopeValidators>
<scopeValidator>XACML Scope Validator</scopeValidator>
</scopeValidators>
<pkceSupportPlain>true</pkceSupportPlain>
<pkceMandatory>false</pkceMandatory>
<userAccessTokenExpiryTime>360000</userAccessTokenExpiryTime>
<applicationAccessTokenExpiryTime>360000</applicationAccessTokenExpiryTime>
<refreshTokenExpiryTime>846000</refreshTokenExpiryTime>
<idTokenExpiryTime>360000</idTokenExpiryTime>
<audiences/>
<bypassClientCredentials>false</bypassClientCredentials>
<requestObjectSignatureValidationEnabled>false</requestObjectSignatureValidationEnabled>
<idTokenEncryptionEnabled>false</idTokenEncryptionEnabled>
<idTokenEncryptionAlgorithm>null</idTokenEncryptionAlgorithm>
<idTokenEncryptionMethod>null</idTokenEncryptionMethod>
<backChannelLogoutUrl></backChannelLogoutUrl>
<tokenType>Default</tokenType>
</oAuthAppDO>
]]></inboundConfiguration>
<Properties/>
</InboundAuthenticationRequestConfig>
<InboundAuthenticationRequestConfig>
<InboundAuthKey>samplesp</InboundAuthKey>
<InboundAuthType>openid</InboundAuthType>
<InboundConfigType>standardAPP</InboundConfigType>
<Properties/>
</InboundAuthenticationRequestConfig>
</InboundAuthenticationRequestConfigs>
</InboundAuthenticationConfig>
<LocalAndOutBoundAuthenticationConfig>
<AuthenticationSteps/>
<AuthenticationType>default</AuthenticationType>
<alwaysSendBackAuthenticatedListOfIdPs>false</alwaysSendBackAuthenticatedListOfIdPs>
<UseTenantDomainInUsername>false</UseTenantDomainInUsername>
<UseUserstoreDomainInRoles>false</UseUserstoreDomainInRoles>
<UseUserstoreDomainInUsername>false</UseUserstoreDomainInUsername>
<EnableAuthorization>false</EnableAuthorization>
</LocalAndOutBoundAuthenticationConfig>
<RequestPathAuthenticatorConfigs/>
<InboundProvisioningConfig>
<ProvisioningUserStore/>
<IsProvisioningEnabled>false</IsProvisioningEnabled>
<IsDumbModeEnabled>false</IsDumbModeEnabled>
</InboundProvisioningConfig>
<OutboundProvisioningConfig>
<ProvisioningIdentityProviders/>
</OutboundProvisioningConfig>
<ClaimConfig>
<RoleClaimURI/>
<LocalClaimDialect>true</LocalClaimDialect>
<IdpClaim/>
<ClaimMappings/>
<AlwaysSendMappedLocalSubjectId>false</AlwaysSendMappedLocalSubjectId>
<SPClaimDialects/>
</ClaimConfig>
<PermissionAndRoleConfig>
<Permissions/>
<RoleMappings/>
<IdpRoles/>
</PermissionAndRoleConfig>
<IsSaaSApp>false</IsSaaSApp>
</ServiceProvider>
The below XACML configuration Denying unless permit with a rule. it is working for permitting just scope_name and username and It does not work for other conditions(client_ip and specific API URI). It should allow the only request that has /sample/.* URIs and for example 10.2.3.4 IP, but I don't know how to do this!!!
<Policy xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" PolicyId="Apolicy2" RuleCombiningAlgId="urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:deny-unless-permit" Version="1.0">
<Target>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-regexp-match">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">/sample/.*</AttributeValue>
<AttributeDesignator AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id" Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true"></AttributeDesignator>
</Match>
</AllOf>
</AnyOf>
</Target>
<Rule Effect="Permit" RuleId="rule-1">
<Target>
<AnyOf>
<AllOf>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">soheyl</AttributeValue>
<AttributeDesignator AttributeId="http://wso2.org/identity/user/username" Category="http://wso2.org/identity/user" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true"></AttributeDesignator>
</Match>
<Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">samplescope</AttributeValue>
<AttributeDesignator AttributeId="http://wso2.org/identity/oauth-scope/scope-name" Category="http://wso2.org/identity/oauth-scope" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true"></AttributeDesignator>
</Match>
</AllOf>
</AnyOf>
</Target>
<Condition>
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-one-and-only">
<AttributeDesignator AttributeId="http://wso2.org/identity/sp/sp-name" Category="http://wso2.org/identity/sp" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true"></AttributeDesignator>
</Apply>
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">samplesp</AttributeValue>
</Apply>
</Condition>
</Rule>
</Policy>

Put one more rule at the end of Rule rule-1 as below and give a try
<Rule Effect="Deny" RuleId="Deny-Rule"/>

Related

Dynamic variable on Tsung XML config file

I've set up TSUNG (v1.7) to test my application, but I'm facing some problem using a dynamic variable on my http request. To be more precise I need to retrieve some data from a CSV file and inserting it in my request.
Reading the documentation it seems that I don't really need to write any sort of functions, since I'm using a version above the 1.3, so to achieve that I just need to specify the file path on the 'option' tag and use the 'setdynvars', but unfortunately it doesn't seems works (the web server response says that the content is empty). Any idea why?
<?xml version="1.0"?>
<!DOCTYPE tsung SYSTEM "/home/Desktop/tsung-1.7.0/tsung-1.0.dtd">
<tsung loglevel="warning">
<clients>
<client host="localhost" use_controller_vm="true"/>
</clients>
<servers>
<server host="127.0.0.1" port="8000" type="tcp"/>
</servers>
<load>
<arrivalphase phase="1" duration="2" unit="minute">
<users interarrival="45" unit="second"/>
</arrivalphase>
</load>
<options>
<option name="file_server" id="transactions" value="/home/Desktop/transactions.csv"/>
</options>
<sessions>
<session name="dummy" weight="1" type="ts_http">
<setdynvars sourcetype="file" fileid="transactions" delimiter=";" order="iter">
<var name="number_transaction"/>
</setdynvars>
<request>
<http url="...path..." method="GET" version="1.1"></http>
</request>
<request subst="true">
<http url='...path...' version='1.1' contents='transaction_id=%%_number_transaction%%' content_type='application/x-www-fomr-urlencoded' method='POST'></http>
</request>
</session>
</sessions>
</tsung>
After some attempt I've figure out that by simply removing the attribute content_type from the request it will make the whole configuration works!

Specify separate data to each user in Tsung

I am using Tsung for load testing. Here is the config file for Tsung.
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE tsung SYSTEM "/usr/share/tsung/tsung-1.0.dtd" []>
<tsung loglevel="warning">
<clients>
<client host="t1" cpu="2" maxusers="30000000"/>
<client host="t2" cpu="2" maxusers="30000000"/>
</clients>
<servers>
<server host="localhost" port="9200" type="tcp"/>
</servers>
<load>
<arrivalphase phase="1" duration="1" unit="minute">
<users arrivalrate="5" unit="second"/>
</arrivalphase>
</load>
</tsung>
But, I want the following:
Only one user per client everytime
Specific data to be read from file for each user. As in, I want to read data from a user1.json for user1 (on client 1) and from user2.json for user2 (on client2).
Is this possible in Tsung? I went through the docs, but didn't find any option to do so. Can someone help me out with this?
Not exactly what you're asking for. But something similar is possible, with one input file.
<options>
<option name="file_server" id="inputUsers" value="/tmp/users.txt"/>
</options>
<sessions>
<session probability="100" name="test" type="ts_http" >
<setdynvars sourcetype="file" fileid="inputUsers" delimiter=";" order="iter">
<var name="userId"/>
<var name="deviceMac"/>
<var name="tKey"/>
</setdynvars>
<request subst="true">
<http url="/abc/%%_userId%%/%%_deviceMac%%?arg=%%_tKey%%" version="1.1"></http>
</request>
<request subst="true">
<http url="/123/%%_userId%%" version="1.1"></http>
</request>
</session>
</sessions>
Where /tmp/users.txt contains colon separated user specific values - something like this (userId;deviceMac;tKey):
97099;05d4e99de98a;4xrwgyyze54kefnwsd74kj4ghvn5f1
Considering the setdynvars order value is "iter", it will iterate through each line, and use that input data as request parameters.
In the above example case, it would make these two requests:
/abc/97099/05d4e99de98a?arg=4xrwgyyze54kefnwsd74kj4ghvn5f1
/123/97099
You can achieve "user specific" load test scenario this way.

Apigee - How to send XML payload using POST method using Apigee API Development Platform

I am supposed to access a a publicly accessible API (https://ABCInsuranceCoreApp.ng.bluemix.net/ABCInsurance/ProductService) using POST method. It accepts an XML Payload of the form
<Customer>
<Age>40</Age>
<Gender>M</Gender>
<Location>IBM</Location>
</Customer>
and returns a list of products. The API works in a REST-Client and tested.
What I have done in the Apigee API Dev Platform is as follows.
Default ProxyEndpoint:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
<Flows>
<Flow name="default">
<Request>
<Step>
<Name>AssignCustomerData</Name>
</Step>
<Step>
<Name>ExecuteProductService</Name>
</Step>
</Request>
<Response>
<Step>
<Name>ParseProductList</Name>
</Step>
</Response>
</Flow>
</Flows>
<HTTPProxyConnection>
<BasePath>/v1/abcinsproductservice</BasePath>
<VirtualHost>default</VirtualHost>
</HTTPProxyConnection>
<RouteRule name="default"/>
</ProxyEndpoint>
AssignCustomerData is an AssignMessage Policy and it looks like..
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="AssignCustomerData">
<DisplayName>AssignCustomerData</DisplayName>
<AssignTo createNew="true" type="request">CustomerData</AssignTo>
<Set>
<Payload contentType="text/xml">
<Customer>
<Age>40</Age>
<Gender>M</Gender>
<Location>IBM</Location>
</Customer>
</Payload>
<Verb>POST</Verb>
</Set>
</AssignMessage>
ExecuteProductService is a service callout and it looks like..
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ServiceCallout async="false" continueOnError="false" enabled="true" name="ExecuteProductService">
<!-- Send the message we just made to the target, and save the result -->
<Request variable="CustomerData"/>
<Response>ProductList</Response>
<HTTPTargetConnection>
<URL>https://ABCInsuranceCoreApp.ng.bluemix.net/ABCInsurance/ProductService</URL>
</HTTPTargetConnection>
</ServiceCallout>
and ParseProductList is an ExtractVriable Policy which looks like..
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ExtractVariables async="false" continueOnError="false" enabled="true" name="ParseProductList">
<DisplayName>ParseProductList</DisplayName>
<FaultRules/>
<Properties/>
<VariablePrefix>products</VariablePrefix>
<XMLPayload>
<Variable name="name" type="string">
<XPath>//Products/Product[1]/Name</XPath>
</Variable>
</XMLPayload>
</ExtractVariables>
I have dilligently followed the samples, however the arrangement does not work. I am confused as to where the error is.
The trace is not working either..
Can you pls help out..
Many thanks in advance
Amitava
I looks like you need to add Source to your ExtractVariables policy, as in:
<Source clearPayload="false">ProductList</Source>
Also, I'm curious why you are doing this with a ServiceCallout (rather than just routing to your target service via a TargetEndpoint)? I don't see a RouteRule in your ProxyEndpoint. Without a RouteRule, you are creating an Echo Server will will simply reflect back whatever comes in. To stop that from happening, you would need to add a RaiseFault policy after your ExtractVariables policy to terminate the call.
Or, perhaps you are just showing us a snippet and there is really more to it?
The way I see it is,
<Step>
<Name>ParseProductList</Name>
</Step>
Should be a Request Step.
So your proxy becomes,
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
<Flows>
<Flow name="default">
<Request>
<Step>
<Name>AssignCustomerData</Name>
</Step>
<Step>
<Name>ExecuteProductService</Name>
</Step>
<Step>
<Name>ParseProductList</Name>
</Step>
</Request>
<Response/>
</Flow>
</Flows>
<HTTPProxyConnection>
<BasePath>/v1/abcinsproductservice</BasePath>
<VirtualHost>default</VirtualHost>
</HTTPProxyConnection>
<RouteRule name="default"/>
</ProxyEndpoint>

Log4j2 Appender attributes with strict xml config

I'm using log4j2-beta9 and want to configure it using a log4j2.xml in strict mode.
My issue is: how do I specify attributes that are not in the shipped schema file?
An Example:
<?xml version="1.0" encoding="UTF-8" ?>
<Configuration
status="DEBUG"
strict="true"
monitorInterval="5"
name="TestingAttributes"
verbose="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="Log4j-config.xsd">
<Properties>
</Properties>
<Appenders>
<Appender
type="Console"
name="SYSERR"
target="SYSTEM_ERR"> <!-- cvc-complex-type.3.2.2: Attribute 'target' is not allowed to appear in element 'Appender'. -->
<Layout Type="PatternLayout">
<Pattern>%date{dd.MM.yyyy HH:mm:ss,SSS} %5p %logger %m%n</Pattern>
</Layout>
<Filters>
<Filter
type="MarkerFilter"
marker="FLOW"
onMatch="DENY"
onMismatch="NEUTRAL" />
<Filter
type="MarkerFilter"
marker="EXCEPTION"
onMatch="DENY"
onMismatch="NEUTRAL" />
</Filters>
</Appender>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="SYSERR" />
</Root>
</Loggers>
</Configuration>
Notice that I want to set the appender to have the target SYSTEM_ERR but the attribute is not allowed in strict mode.
target="SYSTEM_ERR"> <!-- cvc-complex-type.3.2.2: Attribute 'target' is not allowed to appear in element 'Appender'. -->
I could always edit the Log4j-config.xsd and allow that attribute there but that would be kind of wrong also because not all appenders have a target attribute.
As searching the web didn't help me so far, I'm asking you:
Is there anything I'm missing in configuring Log4j2 in strict XML mode?
Do I have to "patch" the XMLConfiguration and the schema file and commit a change to log4j or is there another way besides not using strict mode?
Thanks in advance.
Can you ask this on the log4j-user mailing list? It could be a bug in the schema, but I suspect the schema can do with more improvements and your feedback would be valuable.

Spring security, integrating Facebook authentication into restful basic authentication for mobile application calls

I am developing the server side for a mobile application as per below:
- I'm using Spring MVC framework and I have already implemented BASIC AUTHENTICATION for restful requests (using JSON) as per code below.
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<security:http create-session="stateless" entry-point- ref="restAuthenticationEntryPoint" use-expressions="true">
<security:intercept-url pattern="/restful" access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/restful/*" access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/login" access="permitAll"/>
<security:custom-filter ref="myFilter" after="BASIC_AUTH_FILTER"/>
<!-- <security:logout /> -->
</security:http>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider
user-service-ref="daoUserService">
<security:password-encoder ref="passwordEncoder" />
</security:authentication-provider>
</security:authentication-manager>
<bean id="restAuthenticationEntryPoint" class="com.bp_gae.utils.RestAuthenticationEntryPoint">
</bean>
<bean id="myFilter"
class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager" />
<property name="authenticationEntryPoint" ref="restAuthenticationEntryPoint" />
</bean>
<bean
id="passwordEncoder"
class="com.bp_gae.utils.AppPasswordEncoder" />
<bean
id="daoUserService"
class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property
name="dataSource"
ref="dataSource" />
<property
name="enableGroups"
value="false" />
<property
name="enableAuthorities"
value="true" />
<property name="usersByUsernameQuery">
<value>
select username,password, 1
from users
where username = ?
</value>
</property>
<property name="authoritiesByUsernameQuery">
<value>
select username,authority
from users c,
user_roles cp
where c.user_id = cp.user_id
and c.username = ?
</value>
</property>
</bean>
</beans>
So the mobile client sends username, password in every request and a check in DB is done to determine whether he can have access to protected resources.There are no sessions created. The new requirement is to intagrate Facebook authentication.
1) The mobile user signs in and authenticates on client side and sends the authentication token to server.
2) The server should get user facebook details using that token (check whether this token is valid against facebook) using facebook app-id and app-secret from FB app I've created. I am using Spring Social for that purpose.
3) All protected resources are accessible after either basic or Facebook successful auth.
4) I already have a Users table in DB (username,email,password) and I'm thinking of creating another one with SocialUsers (email, token) and do some matching between them to link same users.
I am not sure on how to get both authentication methods working in my security.xml file.
-Do I have to set up another filter for Social Auth?
-In that case how can I use both filters?
Any suggestions / sample code welcome!

Resources