How to: Spyne authentication? - python

I don't understand how to setup the user and password for authentication of my soap server.
I found this example:
import logging
import random
import sys
# bcrypt seems to be among the latest consensus around cryptograpic circles on
# storing passwords.
# You need the package from http://code.google.com/p/py-bcrypt/
# You can install it by running easy_install py-bcrypt.
try:
import bcrypt
except ImportError:
print('easy_install --user py-bcrypt to get it.')
raise
from spyne.application import Application
from spyne.decorator import rpc
from spyne.error import ArgumentError
from spyne.model.complex import ComplexModel
from spyne.model.fault import Fault
from spyne.model.primitive import Mandatory
from spyne.model.primitive import String
from spyne.protocol.soap import Soap11
from spyne.server.wsgi import WsgiApplication
from spyne.service import Service
class PublicKeyError(Fault):
__namespace__ = 'spyne.examples.authentication'
def __init__(self, value):
super(PublicKeyError, self).__init__(
faultstring='Value %r not found' % value)
class AuthenticationError(Fault):
__namespace__ = 'spyne.examples.authentication'
def __init__(self, user_name):
# TODO: self.transport.http.resp_code = HTTP_401
super(AuthenticationError, self).__init__(
faultcode='Client.AuthenticationError',
faultstring='Invalid authentication request for %r' % user_name)
class AuthorizationError(Fault):
__namespace__ = 'spyne.examples.authentication'
def __init__(self):
# TODO: self.transport.http.resp_code = HTTP_401
super(AuthorizationError, self).__init__(
faultcode='Client.AuthorizationError',
faultstring='You are not authozied to access this resource.')
class SpyneDict(dict):
def __getitem__(self, key):
try:
return dict.__getitem__(self, key)
except KeyError:
raise PublicKeyError(key)
class RequestHeader(ComplexModel):
__namespace__ = 'spyne.examples.authentication'
session_id = Mandatory.String
user_name = Mandatory.String
class Preferences(ComplexModel):
__namespace__ = 'spyne.examples.authentication'
language = String(max_len=2)
time_zone = String
user_db = {
'neo': bcrypt.hashpw('Wh1teR#bbit', bcrypt.gensalt()),
}
session_db = set()
preferences_db = SpyneDict({
'neo': Preferences(language='en', time_zone='Underground/Zion'),
'smith': Preferences(language='xx', time_zone='Matrix/Core'),
})
class AuthenticationService(Service):
__tns__ = 'spyne.examples.authentication'
#rpc(Mandatory.String, Mandatory.String, _returns=String,
_throws=AuthenticationError)
def authenticate(ctx, user_name, password):
password_hash = user_db.get(user_name, None)
if password_hash is None:
raise AuthenticationError(user_name)
if bcrypt.hashpw(password, password_hash) == password_hash:
session_id = (user_name,
'%x' % random.randint(1 << 124, (1 << 128) - 1))
session_db.add(session_id)
else:
raise AuthenticationError(user_name)
return session_id[1]
class UserService(Service):
__tns__ = 'spyne.examples.authentication'
__in_header__ = RequestHeader
#rpc(Mandatory.String, _throws=PublicKeyError, _returns=Preferences)
def get_preferences(ctx, user_name):
if user_name == 'smith':
raise AuthorizationError()
retval = preferences_db[user_name]
return retval
def _on_method_call(ctx):
if ctx.in_object is None:
raise ArgumentError("RequestHeader is null")
if not (ctx.in_header.user_name, ctx.in_header.session_id) in session_db:
raise AuthenticationError(ctx.in_object.user_name)
UserService.event_manager.add_listener('method_call', _on_method_call)
if __name__ == '__main__':
from spyne.util.wsgi_wrapper import run_twisted
logging.basicConfig(level=logging.DEBUG)
logging.getLogger('spyne.protocol.xml').setLevel(logging.DEBUG)
logging.getLogger('twisted').setLevel(logging.DEBUG)
application = Application([AuthenticationService, UserService],
tns='spyne.examples.authentication',
in_protocol=Soap11(validator='lxml'),
out_protocol=Soap11()
)
twisted_apps = [
(WsgiApplication(application), 'app'),
]
sys.exit(run_twisted(twisted_apps, 8000))
When I run this code it gives me access to files from my soap service directory. But my functions for server doesn't work anymore.
How can I configure the soap service to ask for a login and password and then give me access to the server and all the functions?

Related

Python pytest mocking

Sorry I am new to pytest and I am trying to mock a class but I could not make it work as expected.
Can someone help me please?
File test.py:
from easysnmp import Session
class testSnmp: # pylint: disable=too-few-public-methods
"""
class test snmp conifg
"""
def __init__(self, hostname="", **params):
self.hostname = hostname
self.session = Session(
hostname=self.hostname,
version=3,
security_level="auth_with_privacy",
security_username=params["snmp_username"],
auth_protocol="SHA",
auth_password=params["snmp_auth_pwd"],
privacy_protocol="AES",
privacy_password=params["snmp_priv_pwd"],
)
def run_snmp_check(self):
"""
snmp run snmp method
"""
result = {}
result["hostname"] = self.hostname
try:
data = self.session.walk("1.6.6.1.2.1.1.6")
return self.process_data(data)
except Exception:
result["output"] = "Login Failed"
return result
def process_data(self, data=None):
result = {}
result["output"] = []
if data:
if data[0].value == "test":
res = "login succeeded"
else:
res = "Login Failed"
result["hostname"] = self.hostname
result["output"] = res
return result
test file
import pytest
from unittest.mock import Mock, patch, call
import testSnmp
from easysnmp import Session
#mock.patch('test.Session.walk')
#mock.patch('test.Session')
def test_run_snmp_check(mock_walk, mock_sess):
params = {"snmp_username":"b", "snmp_auth_pwd":"c", "snmp_priv_pwd":"d"}
snmp = testSnmp("id_device", **params)
val = [{"id_device":"test"}]
mock_sess_response = Mock()
mock_sess_response.return_value = val
#mock_sess.assert_called_with()
resp = snmp.run_snmp_check()
print(resp)
assert resp == [{"id_device":"test"}]
I am trying to mock session object and walk method but it fails so trying to figure it out.
I have tried similar approach for requests module for http get and post and it works fine.

Custom Python HP ILO Node Exporter not changing hostname by request

Im trying to edit this project in Python to have HP ILO exporter for Prometheus, so far I read a few articles here on stackoverflow and tried to implement some functionalities, eventually I came up to partialy working script but the hostname is not changing after first request, is there a way to dump collector?
I have tried it with try&except but it just does not work.
The goal is to use curl like this
curl localhost:9116/metrics?hostname=ip
And what will happen if there will be 10 requests at the same time with different hostname? Should it create somekind of a queue?
Can someone help me? Thanks
Original Project : https://github.com/JackWindows/ilo-exporter
My code :
#!/usr/bin/env python
import collections
import os
import time
import flask
import redfish
import waitress
from flask import Flask
from prometheus_client import make_wsgi_app
from prometheus_client.core import GaugeMetricFamily, REGISTRY
from werkzeug.middleware.dispatcher import DispatcherMiddleware
from flask import request
from time import sleep
from flask import Flask, Response, request
import traceback
from werkzeug.wsgi import ClosingIterator
class AfterResponse:
def __init__(self, app=None):
self.callbacks = []
if app:
self.init_app(app)
def __call__(self, callback):
self.callbacks.append(callback)
return callback
def init_app(self, app):
# install extension
app.after_response = self
# install middleware
app.wsgi_app = AfterResponseMiddleware(app.wsgi_app, self)
def flush(self):
for fn in self.callbacks:
try:
fn()
except Exception:
traceback.print_exc()
class AfterResponseMiddleware:
def __init__(self, application, after_response_ext):
self.application = application
self.after_response_ext = after_response_ext
def __call__(self, environ, after_response):
iterator = self.application(environ, after_response)
try:
return ClosingIterator(iterator, [self.after_response_ext.flush])
except Exception:
traceback.print_exc()
return iterator
class ILOCollector(object):
def __init__(self, hostname: str, port: int = 443, user: str = 'admin', password: str = 'password') -> None:
self.ilo = redfish.LegacyRestClient(base_url=hostname, username=user, password=password)
self.ilo.login()
system = self.ilo.get('/redfish/v1/Systems/1/').obj
self.label_names = ('hostname', 'product_name', 'sn')
self.label_values = (hostname, system.Model, system.SerialNumber.strip())
def collect(self):
embedded_media = self.ilo.get('/redfish/v1/Managers/1/EmbeddedMedia/').obj
smart_storage = self.ilo.get('/redfish/v1/Systems/1/SmartStorage/').obj
thermal = self.ilo.get('/redfish/v1/Chassis/1/Thermal/').obj
power = self.ilo.get('/redfish/v1/Chassis/1/Power/').obj
g = GaugeMetricFamily('hpilo_health',
'iLO health status, -1: Unknown, 0: OK, 1: Degraded, 2: Failed.',
labels=self.label_names + ('component',))
def status_to_code(status: str) -> int:
status = status.lower()
ret = -1
if status == 'ok':
ret = 0
elif status == 'warning':
ret = 1
elif status == 'failed':
ret = 2
return ret
g.add_metric(self.label_values + ('embedded_media',), status_to_code(embedded_media.Controller.Status.Health))
g.add_metric(self.label_values + ('smart_storage',), status_to_code(smart_storage.Status.Health))
for fan in thermal.Fans:
g.add_metric(self.label_values + (fan.FanName,), status_to_code(fan.Status.Health))
yield g
g = GaugeMetricFamily('hpilo_fan_speed', 'Fan speed in percentage.',
labels=self.label_names + ('fan',), unit='percentage')
for fan in thermal.Fans:
g.add_metric(self.label_values + (fan.FanName,), fan.CurrentReading)
yield g
sensors_by_unit = collections.defaultdict(list)
for sensor in thermal.Temperatures:
if sensor.Status.State.lower() != 'enabled':
continue
reading = sensor.CurrentReading
unit = sensor.Units
sensors_by_unit[unit].append((sensor.Name, reading))
for unit in sensors_by_unit:
g = GaugeMetricFamily('hpilo_temperature', 'Temperature sensors reading.',
labels=self.label_names + ('sensor',), unit=unit.lower())
for sensor_name, sensor_reading in sensors_by_unit[unit]:
g.add_metric(self.label_values + (sensor_name,), sensor_reading)
yield g
g = GaugeMetricFamily('hpilo_power_current', 'Current power consumption in Watts.', labels=self.label_names,
unit='watts')
g.add_metric(self.label_values, power.PowerConsumedWatts)
yield g
label_values = self.label_values + (str(power.PowerMetrics.IntervalInMin),)
g = GaugeMetricFamily('hpilo_power_average', 'Average power consumption in Watts.',
labels=self.label_names + ('IntervalInMin',), unit='watts')
g.add_metric(label_values, power.PowerMetrics.AverageConsumedWatts)
yield g
g = GaugeMetricFamily('hpilo_power_min', 'Min power consumption in Watts.',
labels=self.label_names + ('IntervalInMin',), unit='watts')
g.add_metric(label_values, power.PowerMetrics.MinConsumedWatts)
yield g
g = GaugeMetricFamily('hpilo_power_max', 'Max power consumption in Watts.',
labels=self.label_names + ('IntervalInMin',), unit='watts')
g.add_metric(label_values, power.PowerMetrics.MaxConsumedWatts)
yield g
# Create Flask app
app = Flask('iLO Exporter')
#app.route('/')
def root():
return '''<html>
<head><title>iLO Exporter</title></head>
<body>
<h1>iLO Exporter</h1>
<p><a href='/metrics'>Metrics</a></p>
</body>
</html>'''
AfterResponse(app)
#app.after_response
def say_hi():
print("hi")
#app.route("/metrics")
def home():
try:
REGISTRY.unregister(collector)
except:
print("An exception occurred")
pass
port = int(os.getenv('ILO_PORT', 443))
user = os.getenv('ILO_USER', 'admin')
password = os.getenv('ILO_PASSWORD', 'password')
hostname = request.args.get('hostname')
app.wsgi_app = DispatcherMiddleware(app.wsgi_app, {
'/metrics': make_wsgi_app()
})
collector = ILOCollector(hostname, port, user, password)
REGISTRY.register(collector)
if __name__ == '__main__':
exporter_port = int(os.getenv('LISTEN_PORT', 9116))
waitress.serve(app, host='0.0.0.0', port=exporter_port)

Using attributes of an object in python

I have one class, which is reading data from a JSON file:
import os
import json
from db_connection import DB_Connection
class RA_Admin:
def __init__(self):
data = None
self.load_access_data()
def load_access_data(self):
with open('../docs/db_data.json') as data_file:
self.data = json.load(data_file)
a = RA_Admin()
db_con = DB_Connection(a.data)
db_con.read_data()
I wrote a second class to connect to a database:
import mysql.connector
class DB_Connection:
def __init__(self, data):
database_connection = None
cursor = None
user = data["database"]["user"]
paw = data["database"]["paw"]
ip_address = data["database"]["ip_adress"]
db_name = data["database"]["database_name"]
port = data["database"]["port"]
def read_data(self):
database_connection = mysql.connector.connect(user = self.user, password = self.paw, host=self.ip_address, port=self.port, database=self.db_name)
self.cursor = database_connection.cursor(dictionary=True)
I get the following error:
database_connection = mysql.connector.connect(user = self.user, password = self.paw, host=self.ip_address, port=self.port, database=self.db_name)
AttributeError: DB_Connection instance has no attribute 'user'
I can print the user in the __init__ method and the other attributes, but why are they not used in read_data?
You need self:
self.user = data["database"]["user"]
self.paw = data["database"]["paw"]
....
what-is-the-purpose-of-self-in-python

tornado-redis: LPOP works but BLPOP doesn't?

New to Tornado, and Redis
I find someone had this same problem here , tornado-redis: RPOP works but BRPOP doesn't?
but I still do not understand why, and how to resove my problem
code blow work fine
#coding:utf-8
import random
import time
import tornado.web
import tornado.httpserver
import tornado.ioloop
import tornado.options
from uuid import uuid4
# import redis
from tornado.escape import json_encode
import tornado.gen
import tornadoredis
class noticePush(tornado.web.RequestHandler):
def initialize(self):
print 'initialize'
#tornado.web.asynchronous
#tornado.gen.engine
def get(self):
print 'go here'
try:
**uid = self.get_argument('uid')
# key = u'test_comet%s'%uid
key = 'test_comet1'
c = tornadoredis.Client(host='127.0.0.1', port=6379,password='psw')
print key
res = yield tornado.gen.Task(c.blpop, key, 0)**
print res
if res :
self.finish(json_encode(res))
else :
self.finish('None')
except Exception, e :
print e
pass
class Application(tornado.web.Application):
def __init__(self):
handlers = [
(r'/', noticePush)
]
settings = {
'template_path': 'templates',
'static_path': 'static',
'debug': True
}
tornado.web.Application.__init__(self, handlers, **settings)
if __name__ == '__main__':
tornado.options.parse_command_line()
app = Application()
server = tornado.httpserver.HTTPServer(app)
server.listen(8000)
tornado.ioloop.IOLoop.instance().start()
But , I try to use get_argument for the key, blpop never return any data
**uid = self.get_argument('uid')
key = 'test_comet' + uid
c = tornadoredis.Client(host='127.0.0.1', port=6379, password='psw')
print key
res = yield tornado.gen.Task(c.blpop, key, 0)**
print res
if res :
self.finish(json_encode(res))
else :
self.finish('None')
I try to read the tornadoredis code, find the blpop def and I find the reason
def blpop(self, keys, timeout=0, callback=None):
tokens = to_list(keys)
tokens.append(timeout)
self.execute_command('BLPOP', *tokens, callback=callback)
def to_list(source):
if isinstance(source, str):
return [source]
else:
return list(source)
important is
str_key = 'test_comet', type (key) -> str
unicode_key = 'test_comet' + uid , type (key) -> unicode
when I encode the unicode_key.encode('utf-8'), code worked!

Is this postgresql logging handler correct?

I'm trying to develop a logging handler for PostgreSQL. I've used this gist as a template and changed that to suit my needs as
# -*- coding: utf-8 -*-
import psycopg2
import logging
import time
## Logging handler for PostgreSQL
#
#
class psqlHandler(logging.Handler):
initial_sql = """CREATE TABLE IF NOT EXISTS log(
Created text,
Name text,
LogLevel int,
LogLevelName text,
Message text,
Args text,
Module text,
FuncName text,
LineNo int,
Exception text,
Process int,
Thread text,
ThreadName text
)"""
insertion_sql = """INSERT INTO log(
Created,
Name,
LogLevel,
LogLevelName,
Message,
Module,
FuncName,
LineNo,
Exception,
Process,
Thread,
ThreadName) VALUES (
%(created)s,
%(name)s,
%(levelno)s,
%(levelname)s,
%(msg)s,
%(module)s,
%(funcName)s,
%(lineno)s,
%(exc_text)s,
%(process)s,
%(thread)s,
%(threadName)s
);"""
def connect(self):
try:
self.__connect = psycopg2.connect(
database=self.__database,
host = self.__host,
user = self.__user,
password = self.__password,
sslmode="disable")
return True
except:
return False
def __init__(self, params):
if not params:
raise Exception ("No database where to log ☻")
self.__database = params['database']
self.__host = params['host']
self.__user = params['user']
self.__password = params['password']
self.__connect = None
if not self.connect():
raise Exception ("Database connection error, no logging ☻")
logging.Handler.__init__(self)
self.__connect.cursor().execute(psqlHandler.initial_sql)
self.__connect.commit()
self.__connect.cursor().close()
def emit(self, record):
# Use default formatting:
self.format(record)
if record.exc_info:
record.exc_text = logging._defaultFormatter.formatException(record.exc_info)
else:
record.exc_text = ""
# Insert log record:
try:
cur = self.__connect.cursor()
except:
self.connect()
cur = self.__connect.cursor()
cur.execute(psqlHandler.insertion_sql, record.__dict__)
self.__connect.commit()
self.__connect.cursor().close()
if __name__ == "__main__":
myh = psqlHandler({'host':"localhost", 'user':"test",
'password':"testpw", 'database':"test"})
l = logging.getLogger("TEST")
l.setLevel(logging.DEBUG)
l.addHandler(myh)
for i in xrange(1):
l.info("test%i"%i)
What I would like to know is if this logger is correct (apparently works) and if it would work in a multiprocessing environment.
Thanks.

Categories

Resources