How to authenticate a WAMP connection via a ticket in python - python

I'm trying to connect to a WAMP bus from a different application that has certain roles configured. The roles are authenticated with a static ticket, so I believe that I need to declare what role I want to connect as and what the associated ticket is. I'm writing this in Python and have most of the component set up, but I can't find any documentation about how to do this sort of authentication.
from autobahn.twisted.component import Component, run
COMP = Component(
realm=u"the-realm-to-connect",
transports=u"wss://this.is.my.url/topic",
authentication={
# This is where I need help
# u"ticket"?
# u"authid"?
}
)
Without the authentication, I'm able to connect to and publish to the WAMP bus when it is running locally on my computer, but that one is configured to allow anonymous users to publish. My production WAMP bus does not allow anonymous users to publish, so I need to authenticate what role this is connecting as. The Autobahn|Python documentation implies that it can be done in Python, but I've only been able to find examples of how to do it in JavaScript/JSON in Crossbar.io's documentation.

the documentation is not very up to date.
With the Component it is necessary to do like that for tickets:
from autobahn.twisted.component import Component, run
component = Component(
realm=u"the-realm-to-connect",
transports=u"wss://this.is.my.url/topic",
authentication={
"ticket": {
"authid": "username",
"ticket": "secrettoken"
}
},
)

Here is some example that can be helpful for you:
https://github.com/crossbario/crossbar-examples/tree/master/authentication
I think you need to use WAMP-Ticket Dynamic Authentication method.
WAMP-Ticket dynamic authentication is a simple cleartext challenge
scheme. A client connects to a realm under some authid and requests
authmethod = ticket. Crossbar.io will "challenge" the client, asking
for a ticket. The client sends the ticket, and Crossbar.io will in
turn call a user implemented WAMP procedure for the actual
verification of the ticket.
So you need to create an additional component to Authenticate users:
from autobahn.twisted.wamp import ApplicationSession
from autobahn.wamp.exception import ApplicationError
class AuthenticatorSession(ApplicationSession):
#inlineCallbacks
def onJoin(self, details):
def authenticate(realm, authid, details):
ticket = details['ticket']
print("WAMP-Ticket dynamic authenticator invoked: realm='{}', authid='{}', ticket='{}'".format(realm, authid, ticket))
pprint(details)
if authid in PRINCIPALS_DB:
if ticket == PRINCIPALS_DB[authid]['ticket']:
return PRINCIPALS_DB[authid]['role']
else:
raise ApplicationError("com.example.invalid_ticket", "could not authenticate session - invalid ticket '{}' for principal {}".format(ticket, authid))
else:
raise ApplicationError("com.example.no_such_user", "could not authenticate session - no such principal {}".format(authid))
try:
yield self.register(authenticate, 'com.example.authenticate')
print("WAMP-Ticket dynamic authenticator registered!")
except Exception as e:
print("Failed to register dynamic authenticator: {0}".format(e))
and add Authentication method in the configuration:
"transports": [
{
"type": "web",
"endpoint": {
"type": "tcp",
"port": 8080
},
"paths": {
"ws": {
"type": "websocket",
"serializers": [
"json"
],
"auth": {
"ticket": {
"type": "dynamic",
"authenticator": "com.example.authenticate"
}
}
}
}
}
]

Related

How to link Firebase's Authentication with its Realtime Database in python

I am using the firebase library and I've already tried the pyrebase library too but the database request doesn't seem to be authenticated.
Heres a snippet of my code
import firebase
# I have changed the firebase config details for security purposes, but I still can connect to firebase with my valid credentials
firebase_config = {
'apiKey': "asdfghjkl",
'authDomain': "fir-test-6bb4c.firebaseapp.com",
'projectId': "fir-test-6bb4c",
'storageBucket': "fir-test-6bb4c.appspot.com",
'messagingSenderId': "410996397069",
'appId': "1:410996397069:web:856f4181a8d9debf15b144",
'measurementId': "G-Y0Z6PDGKC2",
'databaseURL': 'https://fir-test-6bb4c-default-rtdb.firebaseio.com/'
}
cloud = firebase.Firebase(firebase_config)
auth = cloud.auth()
db = cloud.database()
storage = cloud.storage()
# Sign In
# for security purposes again, I have changed the email, but it is to confirm that I can authenticate successfully with the right email and password
email = "test1234567#gmail.com"
password = "123456789"
auth.sign_in_with_email_and_password(email, password)
# Connect to Real Time Data Base
uid = auth.current_user["localId"]
path = db.child("users/" + uid)
And here's the database rules
{
"rules": {
".read": false,
".write": false,
"users": {
"$folder": {
".read": "auth != null && auth.uid === $folder",
".write": "auth != null && auth.uid === $folder"
}
},
"secrets": {
".read": false,
".write": false
}
}
}
These are a few things I found out while playing with the rules and in the rules playground:
The firebase/pyrebase database requests are not authenticated even though the authentication at auth.sign_in_with_email_and_password(email, password) was successful
In the rules playground I was able to send authenticated request which allowed me to read and write when the uid and folder name matched
I was also looking for method by which rules could print or log somethings for debug purposes, or if the rules could read and write to the database.
I found out that firestore had the debug() function but I would like to stick to the realtime database since I've been using it for a while.

Microsoft Graph API Synchronisation API, update secret token only works at second call

I'm implementing (in Python with the Microsoft Graph API) the creation of Azure AD application based on the AWS template. I'm stuck when implementing the automatic role provisioning like describe in this documentation : https://learn.microsoft.com/fr-fr/graph/application-provisioning-configure-api?tabs=http#step-3-authorize-access
When I call the servicePrincipals/{id}/synchronization/secrets API for the first time just after the creation of the synchronization job, I receive a HTTP error (400 - Bad Request) with the following body :
{
"error": {
"code": "BadRequest",
"message": "The credentials could not be saved. This is due to an internal storage issue in the Microsoft Azure AD service. For information on how to address this issue, please refer to https://go.microsoft.com/fwlink/?linkid=867915",
"innerError": {
"code": "CredentialStorageBadRequest",
"details": [],
"message": "The credentials could not be saved. This is due to an internal storage issue in the Microsoft Azure AD service. For information on how to address this issue, please refer to https://go.microsoft.com/fwlink/?linkid=867915",
"target": null,
"innerError": {
"code": "CredentialStorageBadRequest",
"details": [],
"message": "Message:The credentials could not be saved. This is due to an internal storage issue in the Microsoft Azure AD service. For information on how to address this issue, please refer to https://go.microsoft.com/fwlink/?linkid=867915",
"target": null
},
"date": "2021-01-05T15:53:59",
"request-id": "---",
"client-request-id": "---"
}
}
}
When a do a second same call (with MS Graph Explorer, Postman or directly in Python), it works, the second call returns an HTTP 204 like expected ! So I think my request is correct.
This is my implementation (which works because I retry the call a second time…) :
# Default value :
GRAPH_API_URL = "https://graph.microsoft.com/beta/{endpoint}"
class Azure:
# […]
# self._http_headers contains my token to access to MS Graph API
# self._aws_key_id and self._aws_access_key contains AWS credentials
def _save_sync_job_auth(self, principal_id):
self._put(
f"servicePrincipals/{principal_id}/synchronization/secrets",
{"value": [
{"key": "ClientSecret", "value": self._aws_key_id},
{"key": "SecretToken", "value": self._aws_access_key},
]},
retry=1 # If I put 0 here, my script fail
)
# […]
def _put(self, endpoint, json, retry=0):
return self._http_request(requests.put, endpoint, retry, json=json)
# […]
def _http_request(self, func, endpoint, retry=0, **kwargs):
url = GRAPH_API_URL.format(endpoint=endpoint)
response = func(url, headers=self._http_headers, **kwargs)
try:
response.raise_for_status()
except requests.HTTPError as e:
if retry:
logging.warning(f"Error when calling {func.__name__.upper()} {url}")
return self._http_request(func, endpoint, retry - 1, **kwargs)
else:
raise e
return response
Am I missing something ? Have you a solution to remove this "retry hack" ?

firebase_admin prints None but I have data in db and permission is allow all [duplicate]

I have a chat app using Firebase that keeps on having a
setValue at x failed: DatabaseError: permission denied
error every time I type a message.
I set my Database to be public already:
service cloud.firestore {
match /databases/{database}/documents {
match /{allPaths=**} {
allow read, write: if request.auth.uid != null;
}
}
}
Is it something from within my chat reference?
private void displayChat() {
ListView listOfMessage = findViewById(R.id.list_of_message);
Query query = FirebaseDatabase.getInstance().getReference();
FirebaseListOptions<Chat> options = new FirebaseListOptions.Builder<Chat>()
.setLayout(R.layout.list_item)
.setQuery(query, Chat.class)
.build();
adapter = new FirebaseListAdapter<Chat>(options) {
#Override
protected void populateView(View v, Chat model, int position) {
//Get reference to the views of list_item.xml
TextView messageText, messageUser, messageTime;
messageText = v.findViewById(R.id.message_text);
messageUser = v.findViewById(R.id.message_user);
messageTime = v.findViewById(R.id.message_time);
messageText.setText(model.getMessageText());
messageUser.setText(model.getMessageUser());
messageTime.setText(DateFormat.format("dd-MM-yyyy (HH:mm:ss)", model.getMessageTime()));
}
};
listOfMessage.setAdapter(adapter);
}
Your code is using the Firebase Realtime Database, but you're changing the security rules for Cloud Firestore. While both databases are part of Firebase, they are completely different and the server-side security rules for one, don't apply to the other.
When you go the database panel in the Firebase console, you most likely end up in the Cloud Firestore rules:
If you are on the Cloud Firestore rules in the Firebase console, you can change to the Realtime Database rules by clicking Cloud Firestore BETA at the top, and then selecting Realtime Database from the list.
You can also directly go to the security rules for the Realtime Database, by clicking this link.
The security rules for the realtime database that match what you have are:
{
"rules": {
".read": "auth.uid !== null",
".write": "auth.uid !== null"
}
}
This will grant any authenticated user full read and write access to the entire database. Read my answer to this question on more on the security/risk trade-off for such rules: Firebase email saying my realtime database has insecure rules.
change this
request.auth.uid != null
to
request.auth.uid == null
or defined a proper auth mechanism before starting the conversation where user defined by userID

How to change the chip suggestions at the order preview?

I want to create a chatbot with Dialogflow and Google Assistant along with Google Transactions API for enabling a user to order a chocolate box. For now my agent contains the following four intents:
Default Welcome Intent (text response: Hello, do you want to buy a chocolate box?)
Default Fallback Intent
Int1 (training phrase: Yes, I want, fulfilment: enabled webhook call)
Int2 (event: actions_intent_TRANSACTION_REQUIREMENTS_CHECK )
I am using Dialogflow Json instead of Node.js to connect my agent with Transactions API. I want to present the order preview (when ordering the chocolate box) by using the actions.intent.TRANSACTION_REQUIREMENTS_CHECK action of Google actions. For this reason, following Google docs, when Int1 is triggered I am using a webhook which connect Google Assistant to the following python script (back-end):
from flask import Flask, render_template, request, jsonify
import requests
app = Flask(__name__)
#app.route("/", methods=['POST'])
def index():
data = request.get_json()
intent = data["queryResult"]["intent"]["displayName"]
if (intent == 'Int1'):
proposedOrder = order.proposed_order(location)
return jsonify({
"fulfillmentText": "This is your order preview:",
"payload": {
"google": {
"expectUserResponse": True,
"isSsml": False,
"noInputPrompts": [],
"systemIntent": {
"data": {
"#type": "type.googleapis.com/google.actions.v2.TransactionDecisionValueSpec",
"orderOptions": {
"requestDeliveryAddress": True,
},
"paymentOptions": {
"actionProvidedOptions": {
"displayName": "VISA **** **** **** 3235",
"paymentType": "PAYMENT_CARD"
}
},
"proposedOrder": proposedOrder
},
"intent": "actions.intent.TRANSACTION_DECISION"
}
}
}
})
if __name__== "__main__":
app.run(debug=True)
where proposed_order is a function which I wrote in the module order which forms the order of the user in the required way specified by Google docs.
When intent == 'Int1' then this will present the order preview to the user (on mobile phone Google Assistant) which looks like this (the example is from Google docs):
As you can see there are three chip suggestions at the bottom of the order preview: Place order, Change payment method, Never mind.
My question is the following: How can I (programmatically) edit these chip suggestions and add mine (e.g. add one chip suggestion 'Change number of items ordered'?
Within the platform's order form, you do not have additional control over what options the user sees. You'd want to have add an intermediary step of the conversation to give them a pre-final check before sending the transaction intent.

Alexa will not play audio from a stream using lambda and python

I can not for the life of me understand why this isnt working.
Here's my lambda function
def lambda_handler(event, context):
url = "https://prod-65-19-131-166.wostreaming.net/kindred-wcmifmmp3-128"
return build_audio_response(url)
def build_audio_response(url):
return {
"version": "1.01",
"response": {
"directives": [
{
"type": "AudioPlayer.Play",
"playBehavior": "ENQUEUE",
"audioItem": {
"stream": {
"token": "sdfsdfsdfsdfsdf3ew234235wtetgdsfgew3534tg",
"url": url,
"offsetInMilliseconds": 0
}
}
}
],
"shouldEndSession": True
}
}
When I run the test in dev portal. I get a response as I should but its missing the directives.
{
"version": "1.01",
"response": {
"shouldEndSession": true
},
"sessionAttributes": {}
}
Alexa just says "There was a problem with the requested skills response."
Well I think its because the directives arent making it over. But I've tested the stream, it works. It's https. Theres a token. What am I missing?
That response from Alexa means that the skill has returned an invalid response that Alexa doesn't know how to parse.
If you haven't already, you should check your CloudWatch logs for the Lambda function to see if any errors are arising there: https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#
To the best of my knowledge, the developer portal still doesn't display directives, so you don't want to test there. From the developer portal Alexa skill test page:
Note: Service Simulator does not currently support testing audio
player directives and customer account linking.
What you can do to debug further if no errors found in CloudWatch is copy/paste the Service Request from that page and use it as a custom test for your Lambda function. On the Lambda page, click the Actions drop down and select Configure Text Event and paste your request from the developer portal into that. That'll give you a better picture of the response you're returning to Alexa. If you can't figure this out, add that response here and we'll try to puzzle things out a bit more.

Categories

Resources