OpenLEADR / openleadr-python

Python library for OpenADR
https://openleadr.org/docs
Apache License 2.0
133 stars 51 forks source link

certs for VEN connection to VTN #67

Closed bbartling closed 3 years ago

bbartling commented 3 years ago

Hi Stan,

I am trying to experiment with using certs for the open ADR authentication. Any chance I could get some tips?

On a new and different cloud linux hosting site (thank for all of the prior Heroku help btw, I can see now that Heroku probably shouldn't be used for open ADR) I can get my remote open Leadr VEN script to connect with my cloud open leader VTN script, but how can I do this with certs? I think I saw in the project road map that .pem support at some point in time... Is cert authentication between client and server available now?

This works from building to cloud Linux hosted VM VTN:

import asyncio
from datetime import datetime, timezone, timedelta
from openleadr import OpenADRServer, enable_default_logging
from functools import partial

enable_default_logging()

async def on_create_party_registration(registration_info):
    """
    Inspect the registration info and return a ven_id and registration_id.
    """
    if registration_info['ven_name'] == 'ven123':
        ven_id = 'ven_id_123'
        registration_id = 'reg_id_123'
        return ven_id, registration_id
    else:
        return False

async def on_register_report(ven_id, resource_id, measurement, unit, scale,
                             min_sampling_interval, max_sampling_interval):
    """
    Inspect a report offering from the VEN and return a callback and sampling interval for receiving the reports.
    """
    callback = partial(on_update_report, ven_id=ven_id, resource_id=resource_id, measurement=measurement)
    sampling_interval = min_sampling_interval
    return callback, sampling_interval

async def on_update_report(data, ven_id, resource_id, measurement):
    """
    Callback that receives report data from the VEN and handles it.
    """
    for time, value in data:
        print(f"Ven {ven_id} reported {measurement} = {value} at time {time} for resource {resource_id}")

async def event_response_callback(ven_id, event_id, opt_type):
    """
    Callback that receives the response from a VEN to an Event.
    """
    print(f"VEN {ven_id} responded to Event {event_id} with: {opt_type}")

# Create the server object
server = OpenADRServer(vtn_id='myvtn',http_host='0.0.0.0')

# Add the handler for client (VEN) registrations
server.add_handler('on_create_party_registration', on_create_party_registration)

# Add the handler for report registrations from the VEN
server.add_handler('on_register_report', on_register_report)

# Add a prepared event for a VEN that will be picked up when it polls for new messages.
server.add_event(ven_id='ven_id_123',
                 signal_name='LOAD_CONTROL',
                 signal_type='x-loadControlCapacity',
                 intervals=[{'dtstart': datetime.now(timezone.utc) + timedelta(minutes=5),
                             'duration': timedelta(minutes=60),
                             'signal_payload': 100.0}],
                 callback=event_response_callback)

# Run the server on the asyncio event loop
loop = asyncio.get_event_loop()
loop.create_task(server.run())
loop.run_forever()

On my building side VEN:

import asyncio
from datetime import timedelta
from openleadr import OpenADRClient, enable_default_logging

enable_default_logging()

async def collect_report_value():
    # This callback is called when you need to collect a value for your Report
    return 1.23

async def handle_event(event):
    # This callback receives an Event dict.
    # You should include code here that sends control signals to your resources.
    print(event)
    return 'optIn'

# Create the client object
client = OpenADRClient(ven_name='ven123',
                         ven_id='ven123',
                       vtn_url='http://11.22.33.44:8080/OpenADR2/Simple/2.0b')

# Add the report capability to the client
client.add_report(callback=collect_report_value,
                  resource_id='device001',
                  measurement='voltage',
                  sampling_rate=timedelta(seconds=10))

# Add event handling capability to the client
client.add_handler('on_event', handle_event)

# Run the client in the Python AsyncIO Event Loop
loop = asyncio.get_event_loop()
loop.create_task(client.run())
loop.run_forever()

I am also working in Python 3.9.5 with the virtual environments as recommended in the docs git cloning the repo. I also notice in the repo that there is example certs (dummy) in a directory too as well as a generate_certificates.sh which ill have to figure out how to use in time.

So any chance for a few tips related too how to change my VEN & VTN scripts to handle certs for authentication greatly appreciated.

Would there be any chance can you help me understand the VEN & VTN open leader API's on what I would all need to pass through to class openleadr.client.OpenADRClient and class openleadr.server.OpenADRServer for how open ADR specifies using certs?

For some reason I dont understand where the fingerprint comes into play between the client/server. Any time you have in response greatly appreciated...

bbartling commented 3 years ago

updated question about certs for open leadr open ADR authentication

stan-janssen commented 3 years ago

Authentication using certificates is definitely supported in the current version of OpenLEADR.

A short explanation of what certificates do in OpenADR is in our documentation here. Certificates allow parties to authenticate, meaning: to prove that they are who they say they are. For this to work, a few things must happen:

bbartling commented 3 years ago

Well cool I think I got this working with certificates now between VEN & VTN. This is just an experiment I have running on a test bench. I ran the generate_certificates.sh on the VTN side and just copied the key.pem & cert.pem to my VEN device certs directory.

Starting the VEN script:

********************************************************************************
                      Your VEN Certificate Fingerprint is
                         B7:63:B8:99:7B:9F:74:7F:9B:89
                  Please deliver this fingerprint to the VTN.
                     You do not need to keep this a secret.
********************************************************************************

I'm still a little bit confused on how to incorporate this Please deliver this fingerprint to the VTN. Is this something I need to do on my VTN script?

VEN script:

# Create the client object
client = OpenADRClient(ven_name='ven123',
                         ven_id='ven123',
                       vtn_url='http://11.22.33.44:8080/OpenADR2/Simple/2.0b',
                         cert='./certificates/certs/cert.pem',
                         key='./certificates/certs/key.pem',
                         passphrase='AmazingSecret!')

VTN script:

# Create the server object
server = OpenADRServer(vtn_id='myvtn',
                       http_host='0.0.0.0',
                       cert='./certificates/certs/cert.pem',
                       key='./certificates/certs/key.pem',
                       passphrase='AmazingSecret!')