Differentiating an "admin" level access for a node in Milo OPC UA project? - opc-ua

While trying to understand the milo project examples for OPC UA based client and server, wanted to get clarified on the following scenario.
When I was trying to test WriteExample with namespace string HelloWorld/OnlyAdminCanWrite/
to connect with server which validates the user with UserNameIdentityToken values "admin" (username) and password2 (password), it was not able to write values.
Is it because the identity is not recognized as admin as seen in the following code in the ExampleNamespace.java file?
node.setAttributeDelegate(new RestrictedAccessDelegate(identity -> {
if ("admin".equals(identity)) {
return AccessLevel.READ_WRITE;
} else {
return AccessLevel.READ_ONLY;
}
How to differentiate the admin from the other users? tested attributes like AccessLevel and UserAccessLevel but they are effective on the current user trying to access.

Thank you for the clarification. Yes you are right, I was using the wrong NodeId. The right NodeId is "HelloWorld/OnlyAdminCanWrite/String" and in order to test WriteExample the Variant value to be written should be a String. Now it works !

Related

Is it "secure" to store a password and username in a .env file in a server to validate an admin API endpoint against?

Context
I've build a RESTful API server in Actix-Web with Rust that's hosted on a Heroku paid plan. It has n amount of publicly available endpoints to access content, alongside 3 strictly admin-only endpoints (for creating, editing, and deleting public content).
I am the only developer who'd ever need to access the admin-only endpoints - and infrequently at that. Several random users will be using the publicly available endpoints daily.
Normally, I'd implement an authentication/authorization strategy akin to this using JWTs (but obviously in Rust for my case). However, the added complexity that comes with this "more common" solution seems overkill for my simple use-case.
My theorized solution
Could I add a username and password field to the .env file in my project like so in order to match against a username and password passed in the admin-only handler functions?
... OTHER KEYS ...
USERNAME = my_really_long_random_username
PASSWORD = my_really_long_random_password
At first glance I'm storing passwords in plain text... but, there's only 1 and it's in my .env file, which is private by default.
All I'd do for the admin-only routes then is this (pseudo-code):
pub fn router_handler(passed_data) -> HttpResponse {
if passed_data.username == env.username && passed_data.password == env.password {
// CONSIDER THEM ADMIN
} else {
// BLOCK THEM AS THEY'RE NOT AUTHENTICATED
}
}
What I've tried
I have yet to try this strategy, but I'm curious about your opinions on it.
Question
Is my theorized solution secure? Does it seem reasonable given my use-case?
Response to question: jthulhu - is this what I do?
So, my .env file should look something like this:
... OTHER KEYS ...
USERNAME = a98ysnrn938qwyanr9c8yQden
PASSWORD = aosdf83h282huciquhr8291h91
where both of those hashes are the results of running my pre-determined username and password through my to_hash function which I added below (likely using a lib like this).
Then, my handler should be like this (psuedo-code):
pub fn router_handler(passed_data) -> HttpResponse {
if to_hash(passed_data.username) == env.username && to_hash(passed_data.password) == env.password {
// CONSIDER THEM ADMIN
} else {
// BLOCK THEM AS THEY'RE NOT AUTHENTICATED
}
}
You should never store passwords in plain text in a server, because if someones breaks in your server, and can read that file, they now have access to everything (whereas they might previously not). Not only that, but most people tend to reuse passwords, so storing one password in plain text means exposing several services where that password is used.
Instead, you should hash the passwords and store the hash. To perform a login, check if the hash of the given password corresponds to the one stored. This mechanism can be used with files or with databases alike, and is pretty much independent on how you actually store the hashes.

Restful web service, partial Read permission

I am designing a restful web service to create and read reports made from an app. When creating a report its possible to add some privacy sensitive information with it like a name, phone number, mail etc. After creating the report its made publicly visible through the same web service.
POST /report
{
"name":"test",
"email":"test#example.com",
"report_contents":....
}
returns 200 OK with:
{
"id":1,
"report_contents":....
}
and a method to get said report:
GET /report/{report_id}
I have another app with which an admin can manage the reports created though the previous web service. In this application I would like to display the privacy sensitive information. It uses the following URL to get a specific report.
GET /report/{report_id}
which returns 200 OK:
{
"id":1,
"name":"test",
"email":"test#example.com",
"report_contents":....
}
Now there is the issue. This is the exact same url. Is it Is it possible/conventional or even a good idea to use the same web service for both calls, but have some kind of CRUD management with it where depending on the role of the user a part of the information is not displayed/blocked? Or would it be better to make a separate web service with restrictions?
Yes, it's OK for different representations of the same resource to be returned at the same URL for different requests. That's how content negotiation works.
If you are concerned about this, I can think of two options:
One option is to include a query parameter to make the choice of views explicit, and access can be controlled for each. E.g.
/report/{report_id}?view=full
/report/{report_id}?view=restricted
Or you could also consider two sub-resources, one called /report/{report_id}/full and one called /report/{report_id}/restricted, and then you can return a 40x code when the user doesn't have correct permission, with a Location header as a hint of where they can look.
If your language of choice supports it, you could return a dynamic object.
here's some pseudo code.
if (loggedInUser != isAdmin(user))
return new { id: 1, contents: "..." }
else
return new { id: 1, name: "test", email: "test#test.com", contents: "..." }
Personally, I would have different areas that do different things. One area that retrieves the model for everyone. In the other it'd be like an admin area.
In the one area, you have

Accessing Firebase with 'user authentication' active using Powershell

I have created a client side app using JavaScript connected to a Firebase database where a user can login and save/edit some data stored Firebase. 'Email and Password' authentication is used as https://www.firebase.com/docs/web/guide/login/password.html
I subsequently wanted to write a Powershell script which would be setup with 'Task Scheduler' to run 1x per day, read each users data and execute some business logic.
I incorrectly expected to be able to whitelist my Server IP to get full access rights to the DB.
If I understood it correctly I need to use 'Custom authentication' using 'JSON Web Tokens (JWTs)', but there are no helper libraries available for Powershell. Had a look at this section https://www.firebase.com/docs/web/guide/login/custom.html#section-tokens-without-helpers but it's not clear to me what needs to be done to get the token.
Can someone give me some pointers or sample code on how to get JWT to work with Firebase/Powershell, or some alternate ways I can get full access to the BD using Powershell?
Thanks in advance
Quintus
I did something that might help you ...
#region TokenGenerator
function TokenGeneretor($secret){
$asm = [Reflection.Assembly]::LoadFile("D:\Firebase\FirebaseTokenGenerator.dll")
$tokenGenerator = [Firebase.TokenGenerator]::new("$secret")
$authPayload = New-Object "System.Collections.Generic.Dictionary``2[System.String,System.Object]"
$authPayload.Add('uid', '1')
$authPayload.Add('some', 'arbitrary')
$authPayload.Add('data', 'here')
$Option = [Firebase.TokenOptions]::new(((Get-Date).AddHours(1)),$null,$true)
$token = $tokenGenerator.CreateToken($authPayload, $Option)
return $token
}
#endregion
TokenGeneretor -secret "123"
The DLL mentioned is the code compiled from https://github.com/firebase/firebase-token-generator-dotNet. Just open the project in Visual Studio and have it compiled. It will play the DLL in the project's DEBUG folder.

Programmatically get user identity from Azure ACS

This question is a bit noobie, but i can't find the information over the internet (perhaps i'm search wrongly?)
We have an Azure ACS configured and we using it as auth service for our website.
But now we need to build an application, which, by known username and password, will receive users claims from ACS. Is this possible?
Yes, it's possible.
One thing to note - Using ACS, you can choose a variety of different token providers to allow (aka STS-es). Each of those provide a different set of claims to you as a default, so you might need to enrich these.
Here's a snippet of code that you can try to see what claims are coming back from ACS in your code already:
// NOTE: This code makes the assumption that you have .NET 4.5 on the machine. It relies on
// the new System.Security.Claims.ClaimsPrincipal and System.Security.Claims.ClaimsIdentity
// classes.
// Cast the Thread.CurrentPrincipal and Identity
System.Security.Claims.ClaimsPrincipal icp = Thread.CurrentPrincipal as System.Security.Claims.ClaimsPrincipal;
System.Security.Claims.ClaimsIdentity claimsIdentity = icp.Identity as System.Security.Claims.ClaimsIdentity;
// Access claims
foreach (System.Security.Claims.Claim claim in claimsIdentity.Claims)
{
Response.Write("Type : " + claim.Type + "- Value: " + claim.Value + "<br/>");
}
Adam Hoffman
Windows Azure Blog - http://stratospher.es
Twitter - http://twitter.com/stratospher_es

Knowing from which udp socket the Radius request came. Using FreeRadius

I know the question isn't very well. Sorry my english.
I want to setup a (one instance of) FreeRadius server to listen to several ports (with a bunch of 'listen' sections) and then pass the that udp port as a parameter along with User-Name and User-Password to a script that I want to use to make the authentication.
The basic idea is make some kind of domain separation. Some Firewall use radius port 2000 to make authentication. Some other different firewall (with a different set of users) use radius port 2020, for example. At the end, all the request fall in the same script that has the knowledge of both set of users and use one or the other according to the given extra attribute (port number)
I know that is possible making a virtual server per 'domain'. but I prefer not to replicate configuration files. and i think is shorter to add a little 'listen' section for every domain I want.
I tried to add an atribute this way:
listen {
ipaddr = *
port = 0
type = auth
update control {
Login-TCP-Port = 1812
}
}
and tried to read it:
autorize {
if ("%{User-Name}" == "bob") {
update reply {
Reply-Message = "This is only %{Login-TCP-Port} an example."
}
update control {
Cleartext-Password := "bob"
}
ok
}
[...]
}
But don't work.
How can i make it right?
Is this posible?
Hope you can help me.
I'm answering myself. I found (looking a like further on google) that the Packet-Dst-Port attribute have the data that I want.
I get it from here (now that I found it, look pretty obvious :P)