Thursday, 2 July 2015

Using Outlook 2016 without Exchange AutoDiscover

re: Problem getting Outlook 2016 connected to Exchange
re: Outlook 2016 is missing Exchange account set-up

Disclaimers:
1. This post is written on 3 July 2015, when Outlook 2016 is still in preview. Nothing is set in stone, but it is very relevant at this point in time.
2. Making changes to the system registry can damage your machine, sometimes even beyond repair. If you do not accept the risks, do not follow these instructions.

Apparently, after several searches on Google for ways to get Outlook 2016 Preview working with our Exchange server, it turns out the option has been removed.  Compare the options available for Outlook 2013 (top) and Outlook 2016 Preview (bottom):

Outlook 2013 Mail Options

Outlook 2016 Mail Options
An Outlook MVP has this to say on the Microsoft Answers forum regarding this change:
Outlook 2016 can only add Exchange accounts using autodiscover. This is a change from Outlook 2013. If you want to use Outlook 2016 with an Exchange account, you need to use autodiscover.
and this
As far as I know, they have no plans to change it. If your employer doesn't have autodiscover configured, you won't be able to use Outlook 2016 to connect using Exchange services.
From my research, there appears to be a window of opportunity in that upgrades from Office 2013 to 2016 can retain the Exchange setup.  This led me to think that connection to Exchange is only broken (intentionally!) from the UI, which is good in the sense that as long as you can get the profile into the system, all will be well again.

It turns out Outlook profiles are stored in the registry.  So, as long as you have a working Outlook 2013 profile somewhere connected to Exchange already, you can "import" it into Outlook 2016 using three simple steps:

  1. Start the registry editor, e.g. Start > Run > Regedit.
  2. Browse to HKEY_CURRENT_USER\Software\Microsoft\Office\15\Outlook\Profiles.
  3. Right-click on "Profiles" and click on "Export". Choose a location to save the registry file.
  4. Edit the registry file saved in step 3, e.g. open in Notepad.
  5. Search for "Office\15.0" and replace-all with "Office\16.0". Save the file.
  6. Double-click on the registry file and answer "Yes" when asked to continue.
  7. Start Outlook 2016 (Preview).
Congratulations, Outlook 2016 is now connected to your Exchange server!


Sunday, 28 June 2015

No-IP Windows Script (VBS) updater

This post concerns Windows clients.  There are plenty of other similar scripts for Linux/OSX - just search on Google.

PowerShell is the future, but there are yet some machines in the past or present. So I chose instead to use plain old tried and true VBS which works for Windows XP through 2012 R2.
Paste the below content into a text document, and give it a good name with an extension of ".vbs".

strFileURL = "https://api.ipify.org"
Set objXMLHTTP = CreateObject("Microsoft.XMLHTTP")
objXMLHTTP.open "GET", strFileURL, false
objXMLHTTP.send()
myIP = objXMLHTTP.responseText
updateURL = "https://dynupdate.no-ip.com/nic/update?hostname=sdrc.ddns.net&myip=" & myIP
Set objXMLHTTP2 = CreateObject("Microsoft.XMLHTTP")
objXMLHTTP2.open "GET", updateURL, false
objXMLHTTP2.setRequestHeader "Authorization", "Basic <your credentials*>"
objXMLHTTP2.setRequestHeader "User-Agent", "Custom NoIP Update Client weonlydo@mailinator.com"
objXMLHTTP2.send()
Use Windows Task Scheduler to run it.  The main trigger to use is "On startup", but because the network interface may not be ready at startup, it may work best to edit the trigger properties and add a small delay (e.g. 30 seconds).  To get maximum coverage, you could have two startup triggers, one immediately, and the other delayed by two minutes.

Some notes about the scheduled task:

  1. Use the System account, or choose a user and provide a password, both will work
  2. You cannot use the VBS file as the "Start Program" directly. Use "cscript" as the program, and the full path of the file in double quotes as the "arguments"
About credentials:

Replace <your credentials> in the script with the base-64 encoded version of your credentials used to log into the No-IP website. e.g. if you log into No-IP using

email: my@email.address
password: mynoippassword

The authorization string would be "Basic bXlAZW1haWwuYWRkcmVzczpteW5vaXBwYXNzd29yZA=="

The site https://www.base64encode.org/ is useful for converting your credentials into the base-64 encoded format.  In the top part, enter "my@email.address:mynoippassword" without quotes and press the "Encode" button.  If you end up with the same code as the above paragraph, congratulations - you have done it correctly.  Now you can encode your own credentials and paste into the script.


References:

Here is the official documentation for updating your Dynamic DNS entry at No-IP.

Thursday, 16 October 2014

CentOS7 Configuring virtual directory to user FTP home

The purpose of this setup is to allow a single user to be able to use FTP to manage the website.
It is achieved by
  1. Changing the Apache service account to the user
  2. Adding the user to the group "apache"
  3. Adding a virtual directory in httpd.conf to within the user's home, e.g. /home/user/www
Steps (assuming user is named demo)
  • sudo usermod -a -G apache demo
  • sudo vi /etc/httpd/conf/httpd.conf
Edit the file as follows:
#User apache    << comment outUser demo       << add as next lineGroup apache
Alias /name "/home/demo/www"    << find a good place<Directory "/home/demo/www">    << and add these 6 lines    AllowOverride All    Options None    Require all granted</Directory>
Note: in my setup, demo has sudoer rights.

Restart Apache
  • sudo systemctl restart httpd
Configure and enable SSH
  • sudo yum -y install mod_ssl
Create self-signed keys with 10 year validity.  For the "Common Name", this is your domain name, or, lacking one, the IP adddress
  • sudo openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /etc/httpd/ssl/apache.key -out /etc/httpd/ssl/apache.crt
Now edit the Apache SSL configuration. Use the same domain name/ip address.
  • sudo vi /etc/httpd/conf.d/ssl.conf
Locate the relevant lines and reconfigure as shown below
# General setup for the virtual host, inherited from global configuration
DocumentRoot "/var/www/html"    <<< uncomment
ServerName 176.31.122.82:443    <<< uncomment, and change server name
SSLCertificateFile /etc/httpd/ssl/apache.crt    <<< change
SSLCertificateKeyFile /etc/httpd/ssl/apache.key   <<< change
Restart Apache
  • sudo systemctl restart httpd
Create users and passwords to use with .htaccess (in the directory that needs to be secured)
  • sudo htpasswd -c ./.htpasswd someusername
  • sudo vi ./.htaccess

Put these lines into the .htaccess file
AuthType BasicAuthName "Authentication required"
AuthBasicProvider fileAuthUserFile /full/path/to/.htpasswdRequire valid-user

Lock down specific directories (URL paths) (using "sudo vi /etc/httpd/conf/httpd.conf")
<Directory "/home/demo/www/protecteddir">
    RedirectPermanent /demo/protecteddir/ https://domain.name.com/demo/protecteddir/
</Directory>

Install PHPMiniAdmin - search Google for this PHP file and FTP it to your new FTP root folder.
Note: It would be a good idea to "hide" it, e.g. rename to 'myhiddenmysqltool.php'
Create a MySQL with a password and a user-owned database

  • create user 'username'@'localhost' identified by 'password';
  • create database username;
  • grant all privileges on username.* to 'username'@'localhost';


CentOS 7 LAMP Installation from scratch

SSH Remotely (Go ahead and type yes, and then enter your root password.)
  • ssh root@123.45.67.890
Change root password
  • passwd
Create new root-level superuser
  • adduser demo
  • passwd demo
Allow this user to run everything that root can
  • visudo
Look for the first line below after comment, and add the 2nd line
# User privilege specification
root ALL=(ALL) ALL
demo ALL=(ALL) ALL 
Change SSH port, and disable remote root login
  • sudo vi /etc/ssh/sshd_config
Find the following sections and change the information where applicable (add the last line):
Port 12345
PermitRootLogin no
AllowUsers demo
Reload SSH
  • systemctl reload sshd.service
Edit "/etc/selinux/config" and change the SELINUX line to "SELINUX=disabled"

New syntax for remote SSH (test this works before disconnecting from root session and rebooting!)
  • ssh -p 12345 demo@123.45.67.890
Reboot server to completely turn off SELinux. It will take a while to relabel all files.

Install Apache, PHP, MySQL (MariaDB)
  • sudo yum install httpd mariadb-server mariadb php php-mysql
Start services and enable for auto-start
  • sudo systemctl start httpd
  • sudo systemctl enable httpd.service
  • sudo systemctl start mariadb
  • sudo systemctl enable mariadb.service
Root for Apache is /var/www/html, so you can test by creating a test file in there with this content
  • <?php phpinfo();
Secure MariaDB
  • sudo mysql_secure_installation
Add common PHP extensions, then restart Apache
  • sudo yum -y install php-gd php-ldap php-odbc php-pear php-xml php-xmlrpc php-mbstring php-snmp php-soap curl curl-devel
  • sudo systemctl restart httpd.service
Install FTP server (VSFTPD)
  • sudo yum install vsftpd ftp -y
  • sudo vi /etc/vsftpd/vsftpd.conf
Find and change this line from YES to NO
  • anonymous_enable=NO
Enable auto-start and start 
  • sudo systemctl enable vsftpd
  • sudo systemctl start vsftpd

references:
https://www.digitalocean.com/community/tutorials/initial-server-setup-with-centos-6
https://www.digitalocean.com/community/tutorials/how-to-install-linux-apache-mysql-php-lamp-stack-on-centos-7

Monday, 2 December 2013

Facebook Page Posts from PHP, the real deal

So I had this need to post to a page (timeline) from a server-side app.
You know, to let the world know something happened somewhere, without user intervention.
It had to post as the page, not as an admin user.

One thing I learnt from this experience is that the Facebook API is really terribly documented with very little actual, usable examples.  The bits of information available on the internet is also quite sparse, outdated (deprecated methods) or irrelevant (Javascript SDK, user dialog etc).

The steps that finally worked for me (not all steps are steps, some are just notes or FYI):

1. If you don't already have a page, you can create one (https://www.facebook.com/pages/create.php)

2. If you already have a page and it has a trailing number, that is your {page id}, e.g. for https://www.facebook.com/pages/yourpagename/123133537809857 the {page id} is 123133537809857

3. Page IDs are unique throughout the Facebook system

4. If you have a page and it looks pretty without a trailing number, one way to get it is to follows the steps from here: http://inlinevision.com/apps/how-to-find-your-facebook-page-id/   To summarize, just right-click and open your page profile picture in a new tab/window.  The URL will look like this:
https://www.facebook.com/photo.php?fbid=xxxxxxxxxxxxxxx&set=a.123456789012345.1234567890.123456789009876&type=1&source=11
The portion in bold is your {page id}

5. Create an app: https://www.facebook.com/developers/createapp.php
If you are asked to sign up as a developer, do so - you have to.
If you don't wish to get stuck like I did, follow the next instructions as closely as possible, verbatim wherever you can.
Give your app a nice display name and a namespace (this ends up as the app URL, i.e .https://apps.facebook.com/{namespace} )
Tick the checkbox to host with heroku.  Go through the sign up, receive an email, set up a password and you're all set with a cloud backend which you never need to look at again (unless you want to).
Save the app settings (button near bottom)

6. Go back to https://developers.facebook.com/apps/. You want to take note of the App ID and App Secret.  Then, click on "Edit Settings".

7. In the "Select how your app integrates with Facebook" section, click once on "App on Facebook" to create a Canvas app (iFrame of external site displaying within FB).  Copy the hosting url (heroku if you followed the step above) and paste it into both Canvas URL and Secure Canvas URL.  Change the Canvas URL from "https://" to "http://".
Save Changes.

8. Browse to this URL from your browser (don't include curly braces):
https://www.facebook.com/dialog/oauth?client_id={your App ID}&redirect_uri={canvas url}&scope=manage_pages,offline_access,publish_stream
You will get three prompts - matching the three permissions you have asked for.  Click OK/Yes to all three.
You have been redirected to:
{canvas url}?code={access token}
Note: The access token is just a very long block of text.
If you botched it, don't worry, you can return to step 8 which will give you a new token, even if you don't have to give permissions anymore.

9. Make up another URL and browse to it:
https://graph.facebook.com/oauth/access_token?client_id={APP ID}&redirect_uri={canvas url}&client_secret={APP SECRET}&code={access token}
Note: {access token} is what you get from the redirected url from the last step
If all goes to plan, you will get a response that looks like this:
access_token={new token}&expires=5183370
Yes, {new token} is also very long.

2013-12-02 Update: Step 10 doesn't seem to work any more. It shows the access, however the token retrieved from step 9 **is** the page access token - just use it.  The response for step 9 also seems to have lost the "expires" parameter.

10. You get the theme, we're big on making up URLs, so here's another one:
https://graph.facebook.com/{your name or id}/accounts/?access_token={new token}
The easiest way to get your facebook "unique name" is to click on your name on the top toolbar. You'll be looking at your "home" page, which looks something like
https://www.facebook.com/{someone.something}
Note: there may be some trailing cruft after the name, e.g.
https://www.facebook.com/SpongeBob?ref=tn_tnmn
You can ignore it. "SpongeBob" is the name we are after for that URL.

11. Browsing to the URL in step 10, you will see one or more blocks of

         "category": ".....",
         "name": "{name of a page you administer}",
         "access_token": "{page access token}",
         "id": "{page id}",
         "perms": [
            "ADMINISTER",
            "EDIT_PROFILE",
            "CREATE_CONTENT",
            "MODERATE_CONTENT",
            "CREATE_ADS",
            "BASIC_ADMIN"
         ]

The most important bits from this are the {page id}, {page access token} and the fact that it has the "CREATE_CONTENT" permission.

(hah - now you know steps 2-4 are in vain. oh well)

You can actually see what Facebook stores in the {page access token} by pasting it in this page:
https://developers.facebook.com/tools/debug/access_token
What you want to verify is that it states "Expires: Never".  Pretty.

12. You now have all the information you need to post as the app to the page, as the page.  Here are some examples depending on what tool you use.

curl command line:
curl -F access_token="{page access token}" \-F message="hello world" \https://graph.facebook.com/{page id}/feed
PHP (error checking excepted):
$ch = curl_init("https://graph.facebook.com/$page_id/feed");curl_setopt($ch, CURLOPT_POST, 1);curl_setopt($ch, CURLOPT_POSTFIELDS, array(        'message' => $message,        'access_token' => $page_access_token));curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);curl_exec($ch);curl_close($ch);

In retrospect, I just didn't follow this post (http://www.apreche.net/tutorial-programatically-post-a-status-update-to-your-facebook-page/) correctly, but there you go. Now you have two interpretations to bank on.

Richard, over and out.

Wednesday, 18 September 2013

Obscure ASP.Net MVC4 WebAPI XML POST parameter

So I had this problem with getting simple XML to be recognized by a Web API controller.

The type that has no namespaces, the type that people cook up in a couple of minutes in Javascript then try to post to a RESTful API.

I started with switching to the XmlSerializer... http://stackoverflow.com/a/11804373/573261. Result is as follows:
System.InvalidOperationException: No MediaTypeFormatter is available to read an object of type 'Job' from content with media type 'application/xml'
I also tried changing the XML (body content) on the fly... http://stackoverflow.com/q/14365953/573261

In between those two attempts were others that you would rather not want to know about, since they obviously led nowhere.

In the end, it turns out that the XML Serializer cannot handle interfaced properties.

        public IList<Item> Items { get; set; }    // fails
        public List<Item> Items { get; set; }    // works

Now you know.

Monday, 19 March 2012

Must have tool - PhpMiniAdmin

So I sit here with a problem.
I have full FTP access to a PHP site, but no access to the MySQL database.
This must be simple, I think - the PHP code can already see it, so let's install phpMyAdmin?
This is when a simple search on Google led me to a wonderful utility - the type I like best, i.e. small and lightweight (29 kB) - phpMiniAdmin (SourceForge)
It has all the bang and wonderful utility of phpMyAdmin, without the 11 MB footprint!
Duly filed away in my Swiss knife folder, truly a must have for remote PHP/MySQL developers.