Reading from a protected page in MediaWiki with a Bot User - mediawiki

Using an admin user I created a dedicated user to own the bot; I added this bot to the 'Bots' group. With this user I logged in and created a BotPassword for my app, and have granted it every possible permission a Bot can have.
I have the following config options defined in my LocalSettings.php
$wgGroupPermissions['*']['read'] = false;
$wgGroupPermissions['bot']['read'] = true;
From my app, I get can successfully login using the Login API - after getting the tokens:
Logging In
{
"login": {
"result":"Success",
"lguserid":11,
"lgusername":"botuser#example.org"
}
}
However, using the following parameters to query for a page:
ArrayList<BasicNameValuePair> queryParameters = new ArrayList<>();
queryParameters.add(new BasicNameValuePair("action", "query"));
queryParameters.add(new BasicNameValuePair("prop", "revisions"));
queryParameters.add(new BasicNameValuePair("rvprop", "content"));
queryParameters.add(new BasicNameValuePair("format", "json"));
queryParameters.add(new BasicNameValuePair("formatversion", "2"));
queryParameters.add(new BasicNameValuePair("rvslots", "main"));
queryParameters.add(new BasicNameValuePair("titles", pageName));
I get the error:
{
"error": {
"code":"readapidenied",
"info":"You need read permission to use this module.",
"docref":"See https://wiki.example.org/api.php for API usage. Subscribe to the mediawiki-api-announce mailing list at <https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce> for notice of API deprecations and breaking changes."
}
}
If I give global read permissions in LocalSettings,
$wgGroupPermissions['*']['read'] = true;
Then my bot user is able to fetch the pages without any errors -
How can I grant permissions to this bot such that I can query for the contents of a page without getting a readapidenied error, while still keeping my Wiki private? Is the BotPassword account in different groups then the main user? If so, how can I change the groups of the bot?
I am running MediaWiki: 1.32.0 on PHP: 7.2.16 and I use ImapAuthorization for user login.

You need to set in Special:BotPasswords what permissions the bot can access. The idea is that your bot password will be stored less securely than your real password (probably included in some bot config file on some shared server) so you'll want to limit what it can be used for.

Related

Is endpoint unique for device in AWS Pinpoint?

I am new to Pinpoint and trying to understand how endpoint/endpointId works in Pinpoint semantics. From the aws doc:
When a user starts a session (for example, by launching your mobile app), your mobile or web application can automatically register (or update) an endpoint with Amazon Pinpoint.
Does that mean each time of the app launching, there is a new endpoint/endpointId? Will it register a new endpoint if the current session ends or the user kill and relaunch the app?
Is there a way I can get the endpoint/endpointId in the app programmatically?
Yes, the endpoint is the same for each unique device, email, etc. It needs to be the same so that Amazon knows where to send push notifications, for example, if you run a targeted campaign. If the user kills and relaunches the app, then the same endpoint is used. This goes for both authenticated and unauthenticated users. Thus, I would have reason to believe that if the current session ends (i.e. the user has to re-authenticate), then they have the same endpoint. This makes sense because every device (the device itself) needs a unique identifier. In order to better answer your question, I have personally tested the below and confirmed:
If one user logs out, and another logs in [on the same device], the endpoint ID remains the same. The purpose of the code below registers a user ID with a specific endpoint. You can also modify the code below to print the endpoint ID, as you requested.
At the top of your AppDelegate, put this, assuming you're using Swift and AWS Cognito for user authentication:
var pinpoint: AWSPinpoint?
... in didFinishLaunching, put this:
self.pinpoint = AWSPinpoint(configuration:AWSPinpointConfiguration.defaultPinpointConfiguration(launchOptions: launchOptions))
if let targetingClient = pinpoint?.targetingClient {
if let username = AppDelegate.defaultUserPool().currentUser()?.username {
let endpoint = targetingClient.currentEndpointProfile()
// Create a user and set its userId property
let user = AWSPinpointEndpointProfileUser()
user.userId = username
// Assign the user to the endpoint
endpoint.user = user
// Update the endpoint with the targeting client
targetingClient.update(endpoint)
print("Assigned user ID \(user.userId ?? "nil") to endpoint \(endpoint.endpointId).\n")
}
}

Laravel 5.4 protected documents on user permission

I have a Laravel project where users have roles with permissions(I'm using
Zizaco/entrust) and the app is accessable just for registered user.
The application holds uploaded documents but this documents should not available for public view, on the other side this documents should be accessable in function of users permission.
My question: how to go in this case, how to protect documents in function of users permission?
I'm not sure if this will help, but you can create a special Controller for downloading/showing a document, where you can check permissions of a actual user.
From Entrust documentation, you can check if user should be able to see the document:
$user->hasRole('owner'); //returns boolean
So you can use this code from below in a Controller:
$user = User::where('username', '=', 'Mark')->first();
$pathToFile = Storage::get('file.pdf');
if ($user->hasRole('admin'))
{
return response()->download($pathToFile); //if you want to display a file, then change download to file
}
else
{
abort(403, 'Unauthorized action.');
}
Remember about adding this line to your controller:
use Zizaco\Entrust\Traits\EntrustUserTrait;
You can read more about responses here: https://laravel.com/docs/5.4/responses and files here: https://laravel.com/docs/5.4/filesystem
Look here for short syntax which will help you implement file downloads in routes.php without creating a new controller.
https://github.com/Zizaco/entrust#short-syntax-route-filter

Accessing Google API from a web application

I've been trying for a couple of days now to crack this but have not had any success.
I have a web application that I want to use with Google Drives API.
I want the web application to check if there is an access token it can use and if not redirect to Google so the user can log in and grant access.
Seemingly a simple task but it's driving me mad! I've checked the Google documentation but it all seems to be geared around console applications
Google provides an interface UserService which stores details of the users using the application. If the users is not logged in redirect the user to login page using:
response.sendRedirect(userService.createLoginURL(request.getRequestURI()))
Later or if the user is logged in, redirect him to "Request for Permission" page using:
List<String> scopes = Arrays.asList(PlusScopes.PLUS_LOGIN,PlusScopes.PLUS_ME,PlusScopes.USERINFO_EMAIL,PlusScopes.USERINFO_PROFILE......); // Add/remove scopes as per your requirement
List<String> responseTypes = Arrays.asList("code");
GoogleAuthorizationCodeRequestUrl gAuthCode = new GoogleAuthorizationCodeRequestUrl(Google project client id, redirect url, scopes);
gAuthCode.setAccessType("offline");
gAuthCode.setClientId(Google project client id);
gAuthCode.setResponseTypes(responseTypes);
gAuthCode.setApprovalPrompt("force");
authURl = gAuthCode.toURL().toString();
response.sendRedirect(authURl);
Make sure you add all required scopes of the API methods you will be using. After the user has accepted, you will have to create a servlet with "/oauth2callback" mapping to get the authorization code.
request.getParameter("code")
In the same servlet using the code obtained, get refresh and access token making a rest call.
URL url = new URL("https://www.googleapis.com/oauth2/v3/token");
HttpURLConnection connection= (HttpURLConnection)url.openConnection();
connection.setRequestMethod("post");
connection.setDoInput(true);
connection.setDoOutput(true);
DataOutputStream dw= new DataOutputStream(connection.getOutputStream());
dw.writeBytes("code="+authorizationCode+"&client_id="+CLIENT_ID+"&client_secret="+CLIENT_SECRET+"&redirect_uri="+REDIRECT_URL+"&grant_type=authorization_code");
dw.flush();
dw.close();
InputStream inputStream= connection.getInputStream();
Parse the input stream to get your refresh token and access token and redirect the user to your landing page.
Now you have access token to query your api whose scopes were provided in authorization flow. Also you have a refresh token which can be used to regenerate new access token if the previously issued access token has expired.
You should be able to implement the OAuthHandshake using HTTP requests and a redirect URL to your web application. You can play around with the requests here to see what the headers and responses look like: https://developers.google.com/oauthplayground/
You can store the authorization code and tokens any way you like. You would have your web application refer to these tokens to see if they are expired. For example:
def getTokenFromFile(self):
creds = self.readCredsFromDisk()
# check if token is expired
expiration_time = datetime.datetime.strptime(creds['token_expiry'], '"%Y-%m-%dT%H:%M:%S.%f"')
if expiration_time < datetime.datetime.now():
self.refreshToken()
# reload creds
creds = self.readCredsFromDisk()
return creds['access_token']
I'm writing just a python script that does the handshake and saves the token to a plain text file. Any time the script runs a function to the Google API it will use this function.
The refresh function:
def refreshToken(self):
with open('client_secret.json') as s:
secret = json.load(s)
secret = secret['installed']
creds = self.readCredsFromDisk()
refresh_url = secret['token_uri']
post_data = {'client_id':secret['client_id'],
'client_secret':secret['client_secret'],
'refresh_token':creds['refresh_token'],
'grant_type':'refresh_token'}
headers = {'Content-type':'application/x-www-form-urlencoded'}
(resp, content) = self.http.request(refresh_url,
method='POST',
body=urlencode(post_data),
headers=headers)
content = json.loads(content)
creds['access_token'] = content['access_token']
date = datetime.datetime.now() + datetime.timedelta(seconds=content['expires_in'])
creds['token_expiry'] = json.dumps(date.isoformat())
self.writeCredsToDisk(json.dumps(creds))
You would write a function similar to this to trade the original authorization code and access code following the logic the OAuth Playground shows you.

XMPPError:forbidden auth error while creating new user using smack 4.1.2

I am trying to create user using smack client 4.1.2. I am getting below error.
Send XML on stream = <<"<iq from='abc.example.com' to='admin#abc.example.com/Smack' id='Dym8b-14' type='error'><query xmlns=jabber:iq:register><password>xxxxxx</password><username>user</username><registered/></query><error code=403 type=auth><forbidden xmlns=urn:ietf:params:xml:ns:xmpp-stanzas/></error></iq>">>
My ejabberd config looks like below (.yml file)
register_from:
admin: allow
...
access_from: register_from
access: register
I am still getting above error. Please help
Adding code snippet to show how I create new user using smack 4.1.0
connection = new XMPPTCPConnection(getConnectionConfiguration());
connection.connect();
connection.login("admin", "admin");
if(connection.isAuthenticated())
{
AccountManager accountManager = AccountManager.getInstance(connection);
accountManager.sensitiveOperationOverInsecureConnection(true);
accountManager.createAccount(userName, password);
connection.disconnect();
// The account has been created, so we can now login
connection.login(userName, password);
}
private XMPPTCPConnectionConfiguration getConnectionConfiguration()
{
XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder()
.setServiceName("abc.example.com")
.setHost("abc.example.com")
.setPort(5222)
.build();
return config;
}
I found the issue. It was due to trusted_network tag had value as loopback:allow in ejabberd config file. I changed it to all:allow. It started working.
The snippet of configuration you provide is too small and badly indented, so it is impossible to tell you what is wrong in your configuration.
However, considering your config is correct, you should check that your user is properly authenticated with the right ACL credentials before sending the register request. Most client libraries assume self user registration and try to send the register before doing any form of authentication.

Retrieving current user's UserId object

I'm writing some code that does administrative tasks on an Exchange server, and I need to set a public folder's permissions, giving myself (that is, the mailbox/user that is connected to Exchange) permissions on a given folder.
The code for this is along these lines:
UserId userId = ???;
myFolder.Permissions.Add(userId, FolderPermissionLevel.Owner);
myFolder.Update();
This code would work fine (and there's no problem with me having permissions to grant myself permissions, since I'm in the Public Folder Management AD group), but the problem is that I don't have UserId object that represents the current user. I don't even have a primarySmtpAddress, which is another way to get a UserId. All I know is that I'm in the context of a user that has permissions to a mailbox - it might be the current Windows user, it might just be a NetworkCredential that was passed to my library.
Is there a way in EWS to get the current user, or at least the current user's SMTP address? I looked in the ExchangeService class but couldn't find anything to that effect.
If you have the NetworkCredential you can bind to AD and use the GetObject to get the IADsUser. From there you can get the email address. Then you can use:
UserIdType user = new UserIdType();
user.PrimarySmtpAddress = "user3#example.com.com";
to set your permissionset userid:
http://msdn.microsoft.com/en-us/library/bb856574(v=exchg.80).aspx