Python Flask enable CORS

Posted: October 24, 2015 in Uncategorized
Tags: , , ,

Install flask-cors plugin

pip install -U flask-cors

Python flask code to enable cors for all resources

from flask import Flask
from OpenSSL import SSL

import os

from flask.ext.cors import CORS
context = SSL.Context(SSL.SSLv23_METHOD)
cer = os.path.join(os.path.dirname(__file__), 'resources/exported-pem.crt')
key = os.path.join(os.path.dirname(__file__), 'resources/exported-pem.key')

app = Flask(__name__)
CORS(app, resources={r"/": {"origins": "*"}, r"/": {"supports_credentials": True}})

@@app.route('/', methods=['POST','GET'])
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
context = (cer, key)
app.run( host='0.0.0.0', port=5000, debug = True, ssl_context=context)

supports_credentials will cause Flask to send “Access-Control-Allow-Credentails” header to true.

Access-Control-Allow-Credentials: true

Please have a look into the below screenshot of cors pre flight OPTION request

Cors preflight OPTION request

Cors preflight OPTION request

Advertisements

Python Flask API in HTTPS

Posted: October 21, 2015 in Uncategorized
Tags: , , , ,

Before starting a server with SSL, you need to create private key and a certificate. I will create a self signed certificate for this tutorial.
Below commands will ask for information regarding your certirficate. Among them, ‘common name’ is the most important inforamtion. It should be the domain name of your server running. This will output two files,

1) udara.com.key –> private key for my domain
2) udara.com.ct –>Self signed certificate

openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout udara.com.key -out udara.com.crt

Below is the Flask code snippet to start your Flask API in HTTPS

from flask import Flask
from OpenSSL import SSL

import os

context = SSL.Context(SSL.SSLv23_METHOD)
cer = os.path.join(os.path.dirname(__file__), 'resources/udara.com.crt')
key = os.path.join(os.path.dirname(__file__), 'resources/udara.com.key')

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'

if __name__ == '__main__':
    context = (cer, key)
    app.run( host='0.0.0.0', port=5000, debug = True, ssl_context=context)

When you run above code, it will show below output. Note that it is running HTTPS

* Running on https://0.0.0.0:5000/ (Press CTRL+C to quit)
* Restarting with stat
  • Add A record
import boto3

client = boto3.client('route53', aws_access_key_id="AWS_KEY", aws_secret_access_key="AWS_SEC_KEY")
hostedZoneId = 'HOSTED_ZONE_ID'

ip= '123.123.123.123'


if aws_region == "US":
    #US is my default region. So cont_code is blank
    cont_code = {}
elif aws_region == "EU":
    cont_code = {'ContinentCode':'EU'}
elif aws_region == "AP":
    cont_code = {'ContinentCode':'AS'}

response = client.change_resource_record_sets(
    HostedZoneId = hostedZoneId,
    ChangeBatch={
        'Comment': 'comment',
        'Changes': [
            {
                'Action': 'CREATE',
                'ResourceRecordSet': {
                    'Name': domain,
                    'Type': 'A',
                    'SetIdentifier': 'my_a_record',
                    'GeoLocation': cont_code,
                    'TTL': 60,
                    'ResourceRecords': [
                        {
                            'Value': ip
                        },
                        ],
                    }
            },
            ]
    }
)


print("DNS record status %s "  % response['ChangeInfo']['Status'])
print("DNS record response code %s " % response['ResponseMetadata']['HTTPStatusCode'])
  • Delete A record

When deleting the A record you only have to change the action to DELETE

'Action': 'DELETE'

The SSL ciphers supported by are the ciphers supported by internal Tomcat server. However you may sometime want customize the ciphers that your server should support. For instance Tomcat support export grade ciphers which will make your server vulnerable to recent FREAK attack. Let’s see how you can define the ciphers.

  • How to view the supporting ciphers

1) Download TestSSLServer.jar jar at http://www.bolet.org/TestSSLServer/TestSSLServer.jar

2) Start the WSO2 server

List the supported ciphers
3) java -jar TestSSLServer.jar localhost 9443

Supported cipher suites (ORDER IS NOT SIGNIFICANT):
TLSv1.0
RSA_WITH_RC4_128_MD5
RSA_WITH_RC4_128_SHA
RSA_WITH_3DES_EDE_CBC_SHA
DHE_RSA_WITH_3DES_EDE_CBC_SHA
RSA_WITH_AES_128_CBC_SHA
DHE_RSA_WITH_AES_128_CBC_SHA
RSA_WITH_AES_256_CBC_SHA
DHE_RSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_RC4_128_SHA
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
(TLSv1.1: idem)
TLSv1.2
RSA_WITH_RC4_128_MD5
RSA_WITH_RC4_128_SHA
RSA_WITH_3DES_EDE_CBC_SHA
DHE_RSA_WITH_3DES_EDE_CBC_SHA
RSA_WITH_AES_128_CBC_SHA
DHE_RSA_WITH_AES_128_CBC_SHA
RSA_WITH_AES_256_CBC_SHA
DHE_RSA_WITH_AES_256_CBC_SHA
RSA_WITH_AES_128_CBC_SHA256
RSA_WITH_AES_256_CBC_SHA256
DHE_RSA_WITH_AES_128_CBC_SHA256
DHE_RSA_WITH_AES_256_CBC_SHA256
TLS_ECDHE_RSA_WITH_RC4_128_SHA
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
———————-
Server certificate(s):
6bf8e136eb36d4a56ea05c7ae4b9a45b63bf975d: CN=localhost, O=WSO2, L=Mountain View, ST=CA, C=US
———————-

  • Configure the preffered ciphers

1) Open [CARBON_HOME]/repository/conf/tomcat/catalina-server.xml and find the Connector configuration corresponding to SSL/TLS. Most probably this is the connector which has port 9443

2) Add a attribute called ciphers which have allowed ciphers in comma separated

<Connector protocol=”org.apache.coyote.http11.Http11NioProtocol”
port=”9443″
bindOnInit=”false”
sslEnabledProtocols=”TLSv1,TLSv1.1,TLSv1.2″
ciphers=”SSL_RSA_WITH_RC4_128_MD5″

Here I have added just one cipher for the simplicity.

3) List the supported ciphers now
java -jar TestSSLServer.jar localhost 9443

Supported versions: TLSv1.0 TLSv1.1 TLSv1.2
Deflate compression: no
Supported cipher suites (ORDER IS NOT SIGNIFICANT):
TLSv1.0
RSA_WITH_RC4_128_MD5
(TLSv1.1: idem)
(TLSv1.2: idem)
———————-
Server certificate(s):
6bf8e136eb36d4a56ea05c7ae4b9a45b63bf975d: CN=localhost, O=WSO2, L=Mountain View, ST=CA, C=US

 

References : http://blog.facilelogin.com/2014/10/poodle-attack-and-disabling-ssl-v3-in.html

When using WSO2 ESB as a JMS consumer you can use ConcurrentConsumers and MaxConcurrentConsumers properties to control the number of threads used to consume messages in the JMS queue or topic.

ConcurrentConsumers is the minimum number of threads for message consuming. If there are more messages to be consumed while those running threads are busy, then additional threads are started until total number of threads reaches MaxConcurrentConsumers. Simply saying, initially “ConcurrentConsumers” of threads are started in order to consume messages. Then if there are more message in the queue/topic yet to be consumed while running threads are busy, additional threads are started in order to consume the remaining messages. Like wise more threads are started untill total number of threads reaches “MaxConcurrentConsumers” number.

Below is a sample JMSListener configuration in axis2.xml. It tells use 5 threads intially and increase number of threads upto 20 according to the load.

&lt;transportReceiver name="jms" class="org.apache.axis2.transport.jms.JMSListener"&gt; 

        &lt;parameter name="myTopicConnectionFactory" locked="false"&gt; 
                &lt;parameter locked="false" name="transport.jms.ConcurrentConsumers"&gt;5&lt;/parameter&gt; 
                &lt;parameter locked="false" name="transport.jms.MaxConcurrentConsumers"&gt;20&lt;/parameter&gt; 
                &lt;parameter name="java.naming.factory.initial" locked="false"&gt;org.apache.activemq.jndi.ActiveMQInitialContextFactory&lt;/parameter&gt; 
                &lt;parameter name="java.naming.provider.url" locked="false"&gt;failover:tcp://localhost:61616&amp;lt;/parameter&gt; 
                &lt;parameter name="transport.jms.ConnectionFactoryJNDIName" locked="false"&gt;TopicConnectionFactory&lt;/parameter&gt; 
                    &lt;parameter name="transport.jms.ConnectionFactoryType" locked="false"&gt;topic&lt;/parameter&gt; 
        &lt;/parameter&gt; 

 

Additionally you can override the values in axis.xml in your proxy too.

In order to understand and test APIs created, WSO2 API manager provides interactive documentation. WSO2AM incoparates swagger[https://developers.helloreverb.com/swagger] for this puprpose.In Swagger, we can define a API using a static JSON file. In APIM, when we create an API, it automatically generates the JSON representation of the API which is loaded by the Swagger. In this tutorial, let’s see how we can edit the JSON representation in order to add some custom header to when calling the API. Below are the steps that are going to do in this tutorial.

  • create an API
  • Use Swagger to invoke the API
  • Describe Swagger documantation
  • Edit Swagger documentation to add a custom header named “username”
  • Invoke the API using Swagger with the newly added header

 

Step1 : Create an API

Design API

 

APi Design

APi Design

Implement API

api-implement

Manage API

api manager

 

Swagger doc.

To view the swagger documentation
Locate to APIM store  ->select the API -> Click on “API Console” tab.

swagger doc

Here you see a header called “Authorization” and a query parameter named “Query Parameter”. However if you want to add another header or query parameter, you have to edit the Swagger documentation of the API.

 

Step2:

Edit Swagger doc

To edit the Swagger documentation
Locate to APIMPublisher -> Select API -> click Docs tab -> Edit Content link

edit

 

swagger doc edit

 

Below is the existing JSON representation of the API we created.

{
    &amp;quot;apiVersion&amp;quot;: &amp;quot;1.0.0&amp;quot;,
    &amp;quot;swaggerVersion&amp;quot;: &amp;quot;1.1&amp;quot;,
    &amp;quot;basePath&amp;quot;: &amp;quot;http://192.168.122.1:8280&amp;quot;,
    &amp;quot;resourcePath&amp;quot;: &amp;quot;/swagger&amp;quot;,
    &amp;quot;apis&amp;quot;: [
        {
            &amp;quot;path&amp;quot;: &amp;quot;/swagger/1.0.0/users&amp;quot;,
            &amp;quot;description&amp;quot;: &amp;quot;&amp;quot;,
            &amp;quot;operations&amp;quot;: [
                {
                    &amp;quot;httpMethod&amp;quot;: &amp;quot;GET&amp;quot;,
                    &amp;quot;summary&amp;quot;: &amp;quot;&amp;quot;,
                    &amp;quot;nickname&amp;quot;: &amp;quot;&amp;quot;,
                    &amp;quot;parameters&amp;quot;: [
                        {
                            &amp;quot;name&amp;quot;: &amp;quot;Query Parameters&amp;quot;,
                            &amp;quot;description&amp;quot;: &amp;quot;Request Query Parameters&amp;quot;,
                            &amp;quot;paramType&amp;quot;: &amp;quot;body&amp;quot;,
                            &amp;quot;required&amp;quot;: false,
                            &amp;quot;allowMultiple&amp;quot;: false,
                            &amp;quot;dataType&amp;quot;: &amp;quot;String&amp;quot;
                        },
                        {
                            &amp;quot;name&amp;quot;: &amp;quot;Authorization&amp;quot;,
                            &amp;quot;description&amp;quot;: &amp;quot;OAuth2 Authorization Header&amp;quot;,
                            &amp;quot;paramType&amp;quot;: &amp;quot;header&amp;quot;,
                            &amp;quot;required&amp;quot;: false,
                            &amp;quot;allowMultiple&amp;quot;: false,
                            &amp;quot;dataType&amp;quot;: &amp;quot;String&amp;quot;
                        }

                    ]
                }
            ]
        }
    ]
}

Under parameters section you can see the already defined header “Authorization”. Let’s add another header “username” by adding the below parameter definition under the “parameters” section.

		{
                            &amp;quot;name&amp;quot;: &amp;quot;username&amp;quot;,
                            &amp;quot;description&amp;quot;: &amp;quot;username of the user&amp;quot;,
                            &amp;quot;paramType&amp;quot;: &amp;quot;header&amp;quot;,
                            &amp;quot;required&amp;quot;: false,
                            &amp;quot;allowMultiple&amp;quot;: false,
                            &amp;quot;dataType&amp;quot;: &amp;quot;String&amp;quot;
                        }

After adding the header representation, whole Swagger documentation of the API is

{
    &amp;quot;apiVersion&amp;quot;: &amp;quot;1.0.0&amp;quot;,
    &amp;quot;swaggerVersion&amp;quot;: &amp;quot;1.1&amp;quot;,
    &amp;quot;basePath&amp;quot;: &amp;quot;http://192.168.122.1:8280&amp;quot;,
    &amp;quot;resourcePath&amp;quot;: &amp;quot;/swagger&amp;quot;,
    &amp;quot;apis&amp;quot;: [
        {
            &amp;quot;path&amp;quot;: &amp;quot;/swagger/1.0.0/users&amp;quot;,
            &amp;quot;description&amp;quot;: &amp;quot;&amp;quot;,
            &amp;quot;operations&amp;quot;: [
                {
                    &amp;quot;httpMethod&amp;quot;: &amp;quot;GET&amp;quot;,
                    &amp;quot;summary&amp;quot;: &amp;quot;&amp;quot;,
                    &amp;quot;nickname&amp;quot;: &amp;quot;&amp;quot;,
                    &amp;quot;parameters&amp;quot;: [
                        {
                            &amp;quot;name&amp;quot;: &amp;quot;Query Parameters&amp;quot;,
                            &amp;quot;description&amp;quot;: &amp;quot;Request Query Parameters&amp;quot;,
                            &amp;quot;paramType&amp;quot;: &amp;quot;body&amp;quot;,
                            &amp;quot;required&amp;quot;: false,
                            &amp;quot;allowMultiple&amp;quot;: false,
                            &amp;quot;dataType&amp;quot;: &amp;quot;String&amp;quot;
                        },
                        {
                            &amp;quot;name&amp;quot;: &amp;quot;Authorization&amp;quot;,
                            &amp;quot;description&amp;quot;: &amp;quot;OAuth2 Authorization Header&amp;quot;,
                            &amp;quot;paramType&amp;quot;: &amp;quot;header&amp;quot;,
                            &amp;quot;required&amp;quot;: false,
                            &amp;quot;allowMultiple&amp;quot;: false,
                            &amp;quot;dataType&amp;quot;: &amp;quot;String&amp;quot;
                        },
{
                            &amp;quot;name&amp;quot;: &amp;quot;username&amp;quot;,
                            &amp;quot;description&amp;quot;: &amp;quot;username of the user&amp;quot;,
                            &amp;quot;paramType&amp;quot;: &amp;quot;header&amp;quot;,
                            &amp;quot;required&amp;quot;: false,
                            &amp;quot;allowMultiple&amp;quot;: false,
                            &amp;quot;dataType&amp;quot;: &amp;quot;String&amp;quot;
                        }

                    ]
                }
            ]
        }
    ]
}

New Swagger Doc

new swagger

 

Now add the new header name to Access-Control-Allow-Headers section of repository/conf/api-manager.xml as below

&lt;Access-Control-Allow-Headers&gt;authorization,Access-Control-Allow-Origin,Content-Type, CustomHeader&lt;/Access-Control-Allow-Headers&gt;

 

HTTP request before and after

Request to the API before

udara@udara$ nc -l 7777
GET http://localhost:7777/users HTTP/1.1
Accept: */*
Host: localhost:7777
Connection: Keep-Alive
User-Agent: Synapse-PT-HttpComponents-NIO

Request to the API after adding the header to the Swagger documentation

udara@udara$ nc -l 7777
GET http://192.168.122.1:7777/users HTTP/1.1
username: udara
Accept: */*
Host: 192.168.122.1:7777
Connection: Keep-Alive
User-Agent: Synapse-PT-HttpComponents-NIO

 

Load balancing with Nginx

Posted: July 24, 2014 in Uncategorized

{Fetch,Decode,Execute & Share}

I am using a simple HTTP server written in Python which will runs on the port given by the commandline argument. The servers will act as upstream servers for this test. Three servers are started
on port 8080,8081 and 8081. Each server logs its port number when a request is received. Logs will be written to the log file located at var/log/loadtest.log. So by looking at the log file, we can identify how Nginx distribute incoming requests among the three upstream servers.

Below diagram shows how Nginx and upstream servers are destrubuted.

Load balancing with Nginx Load balancing with Nginx

Below is the code for the simple HTTP server. This is a modification of [1].

Lets start the servers on port 8080, 8081 and 8081.

Check if the servers are running on the secified ports.

*Configure Nginx as a load balancer for above upstream server.

Create a configuration file in /etc/nginx/udara.com.conf with the below…

View original post 440 more words