Enviroment: IIS 8 behind a Cloudflare Proxy
I'm using Yii2 Access Rules behind Cloudflare to restrict actions by IPS, which works fine when not using a Cloudflare proxy. I'd like to proxy through Cloudflare so I can use some of their features but if I do at present Yii see Cloudflare server addresses not the clients IP.
I believe the Yii2 Acces Rule restricting actions by IPS uses the REMOTE_ADDR header, I would like to use the header HTTP_CF_CONNECTING_IP. Any ideas on how best to achieve this?
Am I best achieving this through Yii2 with an override or IIS itself or...?
You need to configure Request::$trustedHosts to IPs range of your proxy and Request::$ipHeaders to list of allowed headers which will be used to obtain use IP. For example in your web config:
'request' => [
// ...
'trustedHosts' => [
'10.0.2.0/24' => [
'HTTP_CF_CONNECTING_IP',
],
],
'ipHeaders' => [
'HTTP_CF_CONNECTING_IP',
],
],
Make sure that you configure IPs in trustedHosts correctly - all hosts which matches specified range will be able to fake user IP by sending HTTP_CF_CONNECTING_IP header.
You can read more about trusted proxies in guide.
Just to confirm I have this working using the following in my web.config
'request' => [
// ...
'trustedHosts' => [
'103.21.244.0/22' => [
'cf-connecting-ip',
],
// ...
],
'ipHeaders' => [
'cf-connecting-ip',
],
],
Cloudflare IPs can be found here: Cloudflare IP Range
Related
I have two backend applications which use same database. If a user logs into one application and navigate other application url in another tab it loads inner pages without login to that application. Is this possible to restrict that or is this expected functionality?
Application 1 - www.test.com/app1
Application 2 = www.test.com/app2
I have to set who can access one application and who can access second application. Is it possible to do so? Is it possible to do with RBAC? Currently we implement permission based table set and try to check permission when login and navigating pages whether pages have sufficient privileges to do so.
Thanks
You need to change the name for the session cookie that is generated, my guess is that you are experiencing this because the name for the session cookie in both the apps is the same, and you are using the same browser to verify the App2 when you login to APP1, which forces the browser to read the same cookie for the session and finds you are already logged in.
Change them in the configs for both the applications like below
Application 1
'session' => [
// this is the name of the session cookie used for login on the backend
'name' => 'app1-frontend',
'class' => 'yii\web\DbSession',
'cookieParams' => [
'httpOnly' => true,
],
],
Application 1
'session' => [
// this is the name of the session cookie used for login on the backend
'name' => 'app2-frontend',
'class' => 'yii\web\DbSession',
'cookieParams' => [
'httpOnly' => true,
],
],
if you want separate logins for the frontend and backend you can do the same for the frontend and backend configs too.
I've installed mediawiki on an Amazon ec2 server.
The server has only apache, php, mariadb and mediawiki
I'm using mediawiki 1.35, with the bundled VisualEditor and ParsoidPHP
I can use VisualEditor to edit a new page, but it will not save, and when I edit an existing page, I get the blue progress bar followed by the error:
Error contacting the Parsoid/RESTBase server: (curl error: 28) Timeout was reached
I've tried configuring parsoid using instruction I've found on the web :
$wgVirtualRestConfig['modules']['parsoid'] = [
// URL to the Parsoid instance - use port 8142 if you use the Debian package - the parameter 'URL' was first used but is now deprecated (string)
'url' => 'http://myIpAddress:8000',
// Parsoid "domain" (string, optional) - MediaWiki >= 1.26
'domain' => 'myIpAddress',
// Parsoid "prefix" (string, optional) - deprecated since MediaWiki 1.26, use 'domain'
'prefix' => 'myIpAddress',
// Forward cookies in the case of private wikis (string or false, optional)
'forwardCookies' => true,
// request timeout in seconds (integer or null, optional)
'timeout' => null,
// Parsoid HTTP proxy (string or null, optional)
'HTTPProxy' => null,
// whether to parse URL as if they were meant for RESTBase (boolean or null, optional)
'restbaseCompat' => null,
];
The best effect I get is a 404, or a 400. This configuration is not working.
I haven't made any other changes to the settings.
if I call parsoid directly:
http://MyIpAddress/api.php?action=visualeditor&paction=parse&page=Main_Page
I see the timeout thusly:
{
"error": {
"code": "apierror-visualeditor-docserver-http-error",
"info": "Error contacting the Parsoid/RESTBase server: (curl error: 28) Timeout was reached",
"*": "See http://MyIpAddress/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."
}
}
Based on my testing, it appears that parsoid is using the $wgServer variable to make a local connection to rest.php
Using curl, I'm able to connect to http://localhost/rest.php/v1/page/Main_Page
But, not to http://myipaddress/rest.php/v1/page/Main_Page or http://mydomainname/rest.php/v1/page/Main_Page both of these timeout. The apache server can't connect to itself
So, theoretically, I should be able to set
$wgVirtualRestConfig['modules']['parsoid']['domain']='localhost';
But that results in a 404, instead of a timeout.
In the end, I added my domain name to /etc/hosts and pointed it to 127.0.0.1 and that works fine. It feels like a hack, and I must use a domain name, not just an iP.
We've run into this problem several times.
In one case, it was a matter of access control.
Parsoid makes HTTP requests to the MediaWiki site. We're restricting access to certain actions using the Lockdown extension,
and we had to exempt Parsoid, which can be done in several ways, e.g.:
if (($_SERVER['REMOTE_ADDR'] !== '127.0.0.1') && ($_SERVER['REMOTE_ADDR'] !== $_
SERVER['SERVER_ADDR'])) {
# don't lock down any pages for Parsoid, or the VisualEditor will break on them
wfLoadExtension('Lockdown');
}
'urlManagerBackend' => [
'class' => 'yii\web\urlManager',
'baseUrl' => 'http://backend.test',
'enablePrettyUrl' => true,
'showScriptName' => true,
],
then I want to display the image saved under uploads directory
<img src="<?= Yii::$app->urlManagerBackend->baseUrl; ?>/uploads/logo.jpg>
the problem is this url must not be hardcode like this:
'baseUrl' => 'http://backend.test',
The only way how to dynamically determine the domain of the other application (for example the backend from your frontend) would be by parsing the web server's configuration files.
The domain for current application (the one you can get with Url::base(true)) is determined from the request headers or variables set by web server. But those are available only for current application, not for any other application even if they are part of same project.
If you want to parse web server's configuration files than you will have to face three major challenges:
Different web servers have different syntax for configuration files.
Configuration files might be located anywhere.
You might not have access rights to read the configuration files.
So it might be better to try to think about some workaround instead of insisting on determining the domain dynamically.
Make a deploy script that would ask for the backend domain. The one who will be deploying your application on production servers will know the domain for the backend application and can enter it during deployment process. The deploy script will then set the entered backend domain in your configuration files.
Make a page in backend that must be visited before accessing the frontend application. You can determine the domain for backend when the page in backend is visited then set that domain in frontend configuration files. If the frontend is accessed before the domain for backend is set you will only display the notice that the backend page must be accessed first.
In the config folder there should be a file called params.php. If you have something like this
<?php
return [
'adminEmail' => 'admin#example.com',
'baseUrl' => 'http://backend.test',
];
You can use it in your code like this
<img src="<?= Yii::$app->params['baseUrl']; ?>/uploads/logo.jpg>
Then when you move to live, you just need to edit the params.php file.
Too long comment so I need to put it here.
But I'm just wondering in which case that makes sense, except if you are creating web applications, sites, ..., through your application, which I doubt you do.
You know your local domain (use local environment and put urls).
You will know your dev domain (use dev environment and put urls).
You will know your production domain (use prod environment and put urls).
You can also have multiple applications inside yii2 project, so for example,
10 applications across 3 envs, that is 30 urls which you will enter in you configs.
Can you please tell me, how you will access your app if url is dynamically determined -> without using anything else except Yii?
What is your step? You are typing in your browser what? Then we can proceed. Maybe we misunderstand each other.
urlManagerBackend' => [
'class' => 'yii\web\urlManager',
'baseUrl' => 'http://backend.test',
'enablePrettyUrl' => true,
'showScriptName' => true,
]
If you are wondering you can also have multiple urlManagerBackend components across Yii2 environments. Just like with params. Add it on multiple corresponding places at config. So in specific environment you place at same file only key => values which you need to override.
You could simply use Assets and Aliases for this:
If you have a backup/web/uploads/ folder in which you save images uploaded via your backend and you'd like to display those images on your frontend.
Create a new asset file in your frontend/assets/, let's call it BackendAsset.php:
<?php
namespace frontend\assets;
use yii\web\AssetBundle;
class BackendAsset extends AssetBundle {
public $sourcePath = '#backend/web/uploads';
}
where $sourcePath is the backend-folder (source) you'd like to access on the frontend. The #backend alias is predefined in the advanced template, so we'll use it.
Now in our view we can simply use the BackendAsset:
<?php
use frontend\assets\BackendAsset;
$backend = BackendAsset::register($this);
?>
and now we can easily display a file, let's say backend/web/uploads/somefile.jpg:
<img src="<?= $backend->baseUrl . '/somefile.jpg' ?>" >
NOTE: Using the asset in this way copies all the files from the backend/web/uploads to an asset folder in the frontend. To prevent that, you can tell your application not to copy the files, but to link to them (creating SymLinks) instead, unsing linkAssets (yii2 docu):
In your app configuration (in this case frontend/config/main.php), set the linkAssets parameter to TRUE:
'components' => [
'assetManager' => [
'linkAssets' => true,
]
]
I solve this problem by saving the full url in the database.
What about putting a reverseproxy (e.g. nginx) in front of the frontend-server?
Could be configured like:
http://frontend/backend/* -> forwards everyhing to the backend service, the rest will still go to the frontend server.
The configuration (in this case the location of the backend server) of this reverseproxy can be changed any time (also after deployment).
Could that be a viable scenario?
I initially created an app and starting developing it using only the data:read scope. I have now realized that I need the data:create scope as well.
Is there something within the app settings that I need to change?
Does the create scope include read permissions and then write scope include create and read - or does that scope have to be sent separately?
If separately, how is that done when the user is granting permission to the app? Is it something like &scope=data:read&scope:create
I don't have to store and then use two tokens, do I?
How is this handled when using curl? Are the read and create scopes sent in an array like so ...
$response = $client->request('POST', 'https://developer.api.autodesk.com/authentication/v1/gettoken', [
'form_params' => [
'grant_type' => 'authorization_code',
'code' => $authCode,
'client_id' => $FusionID,
'client_secret' => $FusionSecret,
'redirect_uri' => 'https://www.example.com/fusionauth',
'scope' => array('data'=>'create', 'data'=>'read')
]
]);
Again, it may be that you only use the scope you need and you have to store separate tokens, but that doesn't seem right to me.
Is there something within the app settings that I need to change?
If by app settings you meant in the Forge App portal then you only have to specify there the APIs (make sure they are checked on the page) that your app will need to access.
Does the create scope include read permissions and then write scope include create and read - or does that scope have to be sent separately?
No doesn't work like that - you will need to specify each one of them explicitly.
If separately, how is that done when the user is granting permission to the app? Is it something like &scope=data:read&scope:create
Nope the scope variables are delimited by space. For 3-legged oauth you will need to obtain an authorization code through redirecting the user to authenticate at our login portal before you go for access tokens and there you will need to indicate the redirection address and scope combinations in the request URL (don't forget to URLEncode them) such as https://developer.api.autodesk.com/authentication/v1/authorize?response_type=code&client_id=obQDn8P0GanGFQha4ngKKVWcxwyvFAGE&redirect_uri=http%3A%2F%2Fsampleapp.com%2Foauth%2Fcallback%3Ffoo%3Dbar&scope=data:read. See here for details.
And check out our official PHP client SDK - should save you tons of effort and time.
I don't have to store and then use two tokens, do I?
If your token carries sufficient permissions (say data:read and data:create) then no.
How is this handled when using curl? Are the read and create scopes sent in an array like so ...
For cURL see samples here: https://forge.autodesk.com/en/docs/oauth/v2/tutorials/get-2-legged-token/
And like we went through above you will need to specify the scopes when redirecting the user to authenticate so in your request to fetch the eventual access token you'd should something like:
$response = $client->request('POST', 'https://developer.api.autodesk.com/authentication/v1/gettoken', [
'form_params' => [
'grant_type' => 'authorization_code',
'code' => $authCode,
'client_id' => $FusionID,
'client_secret' => $FusionSecret,
'redirect_uri' => 'https://www.example.com/fusionauth'
)
]
]);
I am new to Yii framework.
I have downloaded Yii2, and Yii2 Advanced Application.
I want to create 2 URLs for front and for admin panel.
Front-end URL: http://localhost/advanced
Back-end URL: http://localhost/advanced/admin
How can I do this?
After downloading the Yii2 advanced template archive. Install the advanced Yii2 using this link Yii2 advanced installation guide
Follow all the steps in "Preparing application" section of above url.
After following all steps you are ready to go. Now you can access frontend and backend i.e
For ex:
FRONTEND: http://localhost/advanced/forntend/web
BACKEND: http://localhost/advanced/backend/web
Create admin panel in yii2 backend. Please follow this url Backend Admin panel
I know i am late to answer but i want to help other guys which are new to Yii2. I hope my points will be helpful.
The url routing subject is quite broad. You should start by reading the detailled documentation http://www.yiiframework.com/doc-2.0/guide-runtime-routing.html
Basically, you register an urlManager component in the application config. In the following example, front and admin are 2 controllers with an index action.
new yii\web\Application([
...
'components' => [
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false
'rules' => [
'advanced' => 'front/index'
'advanced/admin' => 'admin/index'
]
],
]
...
])
The advanced application template was never designed to do that because it is two separate applications that requires two separate domains (subdomain for 'admin' is fine).
What you want to use instead is yii2-app-practical-a which does exactly what you want. :)
You have the main application you can access by your main URL - http://localhost/advanced and a back-end you can access by the main URL with admin appended: http://localhost/advanced/admin.