I am writing a custom Java webscript that accepts document noderef and an external username (string value) as parameters. I have auditing enabled and the audit log shows access to the document when I call the webscript. Now I wanted to know if it is possible to modify the audit trail so that when it shows the log for that particular document it also shows the name of the external user.
webscript url: http://localhost:8080/alfresco/service/node/{noderef}/user/{user}
On calling this I get the following output in log:
Extracted audit data:
Application: AuditApplication[ name=alfresco-access, id=1, disabledPathsId=2]
Values:
/alfresco-access/transaction/sub-actions=readContent
/alfresco-access/transaction/action=READ
/alfresco-access/transaction/node=workspace://SpacesStore/c21db432-4ad6-4af2-8bcf-78bc89724afe
/alfresco-access/transaction/type=cm:content
/alfresco-access/transaction/path=/app:company_home/app:shared/cm:audit-services-context.xml
/alfresco-access/transaction/user=admin
New Data:
/alfresco-access/transaction/sub-actions=readContent
/alfresco-access/transaction/action=READ
/alfresco-access/transaction/type=cm:content
/alfresco-access/transaction/user=admin
/alfresco-access/transaction/path=/app:company_home/app:shared/cm:audit-services-context.xml
I want to store the {user} also in the audit trail.
You can try to use AuthenticationUtil.setFullyAuthenticatedUser. I think this should help you. But I didn't test this.
You probably do not want to do that, at least not in the way you describe, not without making extra security precautions.
This goes IMHO opinion against security standards, if admin needs to read a document,the operation needs to be logged with his username, if a normal user needs to access a document, he needs to be properly authenticated for that operation.
Judging from the little context I have I would say this is actually an integration with some other app that does not share SSO with Alfresco. So I would recommend a solution of the following :
Use proper SSO between Alfresco and your application, have the concerned user ping the right endpoint in Alfresco and let SSO authenticate the request properly for you.
Use a shared secret (something like a shared passphrase to encode encode the authority name in the request + proper authentication subsystem or request filter to handle that) or a key pair (something like securecomms between solr and alfresco) to be able to securely pass on authority information to the request
Use a system account (preferably not admin, but one that is dedicated to this usecase/application integration) to generate a valid alf_ticket for the user in question, and have your app attach that ticket to the request. (Of course, your "impersonate" webscript would need to check for the right system/integration username, before running the snippet to get the alf_ticket from a runAsSystem block). In this case, I would also recommend not using the admin account for this but rather use a user with no permissions at all except for this usecase.
If you are going to opt for the quick implementation that you have, I would recommend at least the following :
You need to make sure that not any user can ping that webscript and that only admin/system user can actually access that webscript.
You probably should log the whole impersonation operation in the audit trail (either using the same audit entry or a separate one), so that it would be clear that this is actually an operation that was made on behalf of the user and not directly by the user himself
If you use the webscript in question for anything other than reading the content of the node (Can be the case also if you have a onReadContent behaviour that has some nasty AuthenticationUtil.setFullyAuthenticatedUser as well), and you require that operation to be logged as system/originally authenticated user, You will probably have a hard time doing that... and you should switch to a more robust approach!
Related
REST endpoint design says: Not use verb
In an workflow-like create Employee which has multi-tab style like "Basic Details", "Educational Details", "Work Experience", etc... One first tab data is filled continue button is pushed resulting in an backend API call which just validates the detail in that tab and returns the list of validation errors if any or moves to next tab for the user to fill data. So basically this calls for validate API for each of the tabs with no intention of saving data. Now one thing that comes naturally is below:
POST /employee/basic/validate
(removing api versioning details from endpoint for simplicity)
But using validate in API means verb. How to design then?
There's a separate flow where one can just save "basic details" of employee - so its like any normal API validate and save - so POST /employee/basic/ is good for that case.
REST endpoint design says: Not use verb
That's not a REST constraint - REST doesn't care what spellings you use for your resource identifiers.
All of these URL work, exactly the way that your browser expects them to:
https://www.merriam-webster.com/dictionary/post
https://www.merriam-webster.com/dictionary/get
https://www.merriam-webster.com/dictionary/put
https://www.merriam-webster.com/dictionary/patch
https://www.merriam-webster.com/dictionary/delete
Resources are generalizations of documents; the nature of the HTTP uniform interface is that we have a large set of documents, and a small number of messages that we can send to them.
So if you want a good resource identifier, the important thing to consider is the nature of the "document" that you are targeting with the request.
For instance, the document you are using to validate user inputs might be the validation policy; or you might instead prefer to think of that document as an index into a collection of validation reports (where we have one report available for each input).
Seems that what you try to do in the end is to run your operation in dry-run mode.
My suggestion would be to add a dry-run option as request parameter for instance.
/employee/basic?dry-run=true
REST says that you should use standards like HTTP to achieve a uniform interface. There are no URL standards as far as I know, even OData says that its URL naming conventions are optional.
Another thing that the browser is a bad REST client. REST was designed for webservices and machine to machine communication, not for the communication of browsers with webapplications, which is sort of human to machine communication. It is for solving problems like automatically order from the wholesaler to fill my webshop with new items, etc. If you check in this scenario both the REST service and REST client are on servers and have nothing to do with the browser. If you want to use REST from the browser, then it might be better to use a javascript based REST client. So using the browser with HTML forms as a REST client is something extreme.
If you have a multitab form, then it is usually collected into a session in regular webapplications until it is finalized. So one solution is having a regular webapplication, which is what you actually have, since I am pretty sure you have no idea about the mandatory REST constraints described by Fielding. In this case you just do it as you want to and forget about REST.
As of naming something that does validation I would do something like POST /employee/basic/validation and return the validation result along with 200 ok. Though most validation rules like "is it a date", "is it a number", etc. can be done on the clients currently they can be done even in HTML. You can collect the input in a session on server or client side and save it in the database after finilazing the employee description.
As of the REST way I would have a hyperlink that describes all the parameters along with their validations and let the REST client make tabs and do the REST. At the end the only time it would communicate with the REST service is when the actual POST is sent. The REST client can be in browser and collect the input into a variable or cookies or localstorage with javascript, or the REST client can be on server and collect the input into a server side session for example. As of the REST service the communication with it must be stateless, so it cannot maintain server side session, only JWT for example where all the session data is sent with every request.
If you want to save each tab in the webservice before finalizing, then your problem is something like the on that is solved with the builder design pattern in programming. In that case I would do something like POST /employeeRegistrationBuilder at the first step, and which would return a new resource something like /employeeRegistrationBuilder/1. After that I can do something like PUT/POST /employeeRegistrationBuilder/1/basics, PUT/POST /employeeRegistrationBuilder/1/education, PUT/POST /employeeRegistrationBuilder/1/workExperience, etc. and finalize it with PUT/POST /employeeRegistrationBuilder/1/finished. Though you can spare the first and the last steps and create the resource with the basics and finish it automagically after the workExperience is sent. Cancelling it would be DELETE /employeeRegistrationBuilder/1, modifying previous tabs would be PUT/PATCH /employeeRegistrationBuilder/1/basics. Removing previous tabs would be DELETE /employeeRegistrationBuilder/1/basics.
A more general approach is having a sort of transaction builder and do something like this:
POST /transactions/ {type:"multistep", method: "POST", id: "/employee/"}
-> {id: "/transactions/1", links: [...]}
PATCH /transactions/1 {append: "basics", ...}
PATCH /transactions/1 {append: "education", ...}
PATCH /transactions/1 {remove: "basics", ...}
PATCH /transactions/1 {append: "workExperience", ...}
PATCH /transactions/1 {append: "basics", ...}
...
POST /employee/ {type: "transaction", id: "/transactions/1"}
-> /employee/123
With this approach you can create a new employee both in multiple steps or in a single step depending on whether you send actual input data or a transaction reference with POST /employee.
From data protection (GDPR) perspective the transaction can be the preparation of a contract, committing the transaction can be signing the contract.
I want to retrieve UserPrincipalName of current logged in user using java.I can connect to AD and retrieve that, but i want to avoid all those configuration and other stuff, is there an easier way to get UPN using java?
UPN stored in AD is usually in userName#domainName format. If my user is john and domain is vmware, it should return john#vmware.
Please advise.
Java and JavaScript are separate languages. For a java servlet you can get the UserPrinciple name property with
GetPageContext().getRequest().getUserPrincipal().getName()
For javascript you'd need to have the server provide this via rendering it as a value, or have some framework or AJAX that allows the user principle be added to the response data or callable via the page script.
I got a question about security for my simple REST API application.
I implemented check for security and on every attempt to read/update data from/in database (this is a simple HttpSession session= request.getSession(true); and check - if this is a new session or old and if it equals session id fro cookies).
But the thing is - even if this is a valid user and valid session - I got an URL which make a user to ignore other user:
http://localhost:8080/ChatRest/rest/FriendService/ignoreFriend/1/2
I could change 2 users id (last 2 numbers) and send the same request to make other system user to ignore somebody else, for example: http://localhost:8080/ChatRest/rest/FriendService/ignoreFriend/3/4
How can I solve this problem?
I googled a lot (for example - RESTful Authentication and related articles, including security questions). But what is the easiest way to solve this problem? I quite a beginner, so I'll be happy to find the simpliest solutions.
Thank you!
Any authentication mechanism allows you to handle this, provided that users don't share the same credentials. Even with Basic AUTH, you'll be able to determine who authenticated.
If the logged in user is id=1, then he can perform http://localhost:8080/ChatRest/rest/FriendService/ignoreFriend/1/2, but he can't ignore people for any other id. In fact, since you get the user id from the database, you don't even need the first parameter. It would be ignoreFriend/2, meaning "I want to ignore the person whose id I'm giving as a parameter".
I'm sure this is basic and I'm missing something. I've read through other answers on SO, I've googled, I've read resources and I just can't wrap my head around what I need to do.
I'm trying to figure out how to write an app that connects to Twitch's API, specifically how to authenticate with Twitch's api. Their documentation is here: https://github.com/justintv/Twitch-API/blob/master/authentication.md
I've created an app and stored my keys.
Now comes the part where I want my user to click a button which launches the authentication on their website. From what I can tell I do this by using an AccountManager. Except... I can't figure out what I'm supposed to do.
Here's the excerpt I've found online:
AccountManager am = AccountManager.get(this);
Bundle options = new Bundle();
am.getAuthToken(
myAccount_, // Account retrieved using getAccountsByType()
"Manage your tasks", // Auth scope
options, // Authenticator-specific options
this, // Your activity
new OnTokenAcquired(), // Callback called when a token is successfully acquired
new Handler(new OnError())); // Callback called if an error occurs
According to twitch's documentation I want to send the user to:
https://api.twitch.tv/kraken/oauth2/authorize
?response_type=code
&client_id=[your client ID]
&redirect_uri=[your registered redirect URI]
&scope=[space separated list of scopes]
&state=[your provided unique token]
And I simply have no idea how these two things need to be combined.
Firstly, I recommend to read the OAuth2 RFC. This should cover everything you need to know.
The AccountManager code snippet won't help you much unless there already is an app that provides authentication for Twitch. If that's not the case you either need to use an existing OAuth2 library or implement your own.
You could write your own AccountAuthenticator but that's a different challenge (and you still need some kind of OAuth2 client).
Doing it yourself is not that hard, see below.
Steps to implement it yourself
Twitch recommends to use the "Implicit Grant Flow" for mobile apps. That's what I'm going to describe below.
1. Get a client ID
Register your app as outlined in Developer Setup to get a client ID
As redirect URI you can use something like https://localhost:12398/, the actual port doesn't really matter.
2. Build the authentication URL
In your client app you need to construct the authentication URL like so:
https://api.twitch.tv/kraken/oauth2/authorize?
response_type=token&
client_id=[your client ID]&
redirect_uri=[your registered redirect URI]&
scope=[space separated list of scopes]
Apparently [your client ID] should be replaced by the client ID you've received from Twitch, same goes for [your registered redirect URI] (that's the URL above, i.e. https://localhost:12398/). [space separated list of scopes] is the list of scopes (i.e. features your want to access), see Scopes. Make sure you URL-encode the parameter values properly.
Assuming your client ID is 123456 and the scopes you need are user_read and channel_read your URL would look like this:
https://api.twitch.tv/kraken/oauth2/authorize?
response_type=token&
client_id=123456&
redirect_uri=https%3A%2F%2Flocalhost%3A12398%2F&
scope=user_read%20channel_read
Note that you should also pass a state parameter, just use a randomly generated value. You can also append the (non-standard) force_verify parameter to make sure the user actually needs to log in each time (instead of continuing a previous session), but I think you can achieve the same by clearing the cookie store (given that you open the URL in a webview in the context of your app) before you open the login page.
With a random state the URL would look like this:
https://api.twitch.tv/kraken/oauth2/authorize?
response_type=token&
client_id=123456&
redirect_uri=https%3A%2F%2Flocalhost%3A12398%2F&
scope=user_read%20channel_read&
state=82hdknaizuVBfd9847guHUIhndzhuehnb
Again, make sure the state value is properly URL encoded.
3. Open the authentication URL
Ideally you just open the URL in a WebView inside of your app. In that case you need to intercept all request to load a new URL using WebViewClient.shouldOverrideUrlLoading
Once the client is redirected to your redirect URL you can close the webview and continue with step 4.
Theoretically it's possible to utilize the default browser to do the authentication, but I would have security concerns since an external app could learn about your client ID and the access token.
4. Extract the access token
The actual URL you get redirected to in step #3 will have the form:
https://[your registered redirect URI]/#access_token=[an access token]&scope=[authorized scopes]
or to pick up the example
https://localhost:12398/#access_token=xxx&scope=user_read%20channel_read
Where xxx is the actual access token.
If you passed a state it will be present like so:
https://localhost:12398/#access_token=xxx&scope=user_read%20channel_read&state=82hdknaizuVBfd9847guHUIhndzhuehnb
All you have to do now is to parse the (URL encoded) access token, scope and state. Compare the scopes and state to the ones that you actually sent. If they match you can start using the access_token to authenticate.
Note According to the OAuth2 RFC, the response URL MUST also contain a token_type and it SHOULD contain an expires_in duration in seconds.
Once you received the access token you can use it to authenticate as described here.
Access tokens issued by the Implicit Grant Flow usually expire after a certain time and the user needs to authenticate again. The Twitch documentation doesn't mention any expiration time, so it's possible that the token is valid forever. So make sure your app doesn't store it or store it in a secure way (like using Android's key store provider to generate and store a key to encrypt the access token).
If the implicitly issued access token expires you could consider using the "Authorization Code Flow". That's quite similar but it contains an additional step to receive the access token and a "refresh token" that can be used to renew the access token. I leave it up to you to figure out how that works.
I want to access Subscription's REST,
For instance ;
/store/{storeId}/subscription?q=byBuyerIdAndSubscriptionType
Ref:https://www-01.ibm.com/support/knowledgecenter/SSZLC2_7.0.0/com.ibm.commerce.starterstores.doc/code/rsm_subscription_fep8.htm?lang=en
but if I explicitly pass member_id of the buyer of subscription to the REST call on some other user's login, it gives me authentication error and doesn't return anything.
User 2581 does not have the authority to perform action "Display" on resource "com.ibm.commerce.subscription.facade.server.authorization.SubscriptionTypeProtectableProxy" for command "Display".
What should I do to byPass this authentication and get desired data?
You could try giving this line in your wc-rest-security.xml file.
<partialAuthentication resource="store/{storeId}/" method="GET" enabled="false"/>
You could also be specific and mention
store/{storeId}/subscription
instead of
store/{storeId}/
I haven't verified the above line, but I am pretty sure the solution to your issue lies in configuring the wc-rest-security.xml file. Link to the IBM Documentation on this : https://www-01.ibm.com/support/knowledgecenter/SSZLC2_8.0.0/com.ibm.commerce.webservices.doc/tasks/twvrestpartialauth.htm
You shouldn't. For obvious reasons.
You should not allow access to other users' subscription data. If what you're trying to accomplish is to allow specific users access to other users' data (e.g. a CSR), then you need to solve this through access control policies and appropriate user roles.