Tuesday 1 August 2017

JIRA Server installation

These are the steps I went through to install and configure a TEST/DEMO Jira Server on Microsoft Azure Windows VM in the cloud.
We will also be importing from Mantis (MySQL) to test the migration process.

Azure VM

  1. Provision an Azure VM, DS2_V2. We won't be keeping it up 24/7 so price doesn't matter too much. Note: I used Windows 2016 Datacentre
  2. Create a DNS name <something>.fnzbasakljira.australiasoutheast.cloudapp.azure.com so you never need to look at the IP address (but we do - later).
  3. Configure network security group to allow ports 80/443. 80 for free SSL, 443 for actual secure use later.
  4. Log onto VM
  5. What I always do: Turn off IESC and install the ubiquitous tools - Notepad++, 7-Zip
  6. In Windows Firewall, add an inbound rule to allow HTTP/S (TCP 80, 443)
JIRA (v7.4.2#74004)
  1. Download and install JIRA - choose the Express/Demo option
  2. Use the custom/expert mode
  3. Follow the steps to create a key for a 90 day trial
  4. Choose port 80 instead of 8080
SSL
  1. Create a DNS record to point to the VM's IP address
  2. Go to https://sslforfree.com and follow the steps to create a certificate
  3. Use the option for Manual Verification
  4. On the Azure VM, create the folder structure C:\Program Files\Atlassian\JIRA\well-known\acme-challenge\FeDY-uMBdrY4SWhoTjwCe7XT9lXxv7nKNUW9b_wOUV0 where the last folder name is the name of the file expected, e.g. 
    1. http://my.domain.com/.well-known/acme-challenge/FeDY-uMBdrY4SWhoTjwCe7XT9lXxv7nKNUW9b_wOUV0/
  5. In the folder, save the file ("Download file #1") from the SSLforFree verification link and rename it as index.htm
  6. Edit the file C:\Program Files\Atlassian\JIRA\conf\server.xml and add this line before the similar <Context path="" line
    1. <Context path="/.well-known" docBase="${catalina.home}/well-known" reloadable="false" useHttpOnly="true" />
  7. Click "Download SSL Certificate"
  8. Click "Download All SSL Certificate Files" on the next page
  9. You now have certificate.crt, private.key and ca_bundle.crt
  10. Download OpenSSL binaries for Windows. I used the slproweb link from https://wiki.openssl.org/index.php/Binaries
  11. For the next step, easier to copy the 3 files into the same folder as openssl.exe, then delete them after.
  12. Run the command line (in openssl.exe folder) (you can change the highlighted name):

    C:\OpenSSL-Win32\bin>openssl pkcs12 -export -in certificate.crt -inkey private.key -out cert.p12 -name SSLForFree -CAfile ca_bundle.crt -caname root
  13. Then, in the cmd.exe console swith to JIRA's JRE bin folder and run this:

    keytool -importkeystore -deststorepass changeit -destkeystore "C:\Program Files\Atlassian\JIRA\jre\lib\security\cacerts" -srckeystore C:\OpenSSL-Win32\bin\cert.p12 -srcstoretype PKCS12 -srcstorepass yourPfxPassword

    keytool -storepasswd -new yourPfxPassword -keystore "C:\Program Files\Atlassian\JIRA\jre\lib\security\cacerts"

    Using your password from step 12
  14. In cmd.exe, set the environment variable for Java

    SET JRE_HOME=C:\Progra~1\Atlassian\JIRA\jre
  15. Run the JIRA configuration utility

    C:\Program Files\Atlassian\JIRA\bin>config.bat
  16. In the Web Server tab, change:

    Profile: HTTP and HTTPS (redirect)
    HTTPs Port: 443
    Keystore Path: 
    C:\Program Files\Atlassian\JIRA\jre\lib\security\cacerts
    Keystore Password: yourPfxPassword
  17. Use "Check Certificate in Key Store" button to ensure everything is correct before clicking Save then Close
  18. As at 2nd August 2017, the JIRA configuration utility puts the wrong connector into the server.xml (see step 6 for path) file when HTTPS is enabled. Look for org.apache.coyote.http11.Http11Protocol and change it to org.apache.coyote.http11.Http11NioProtocol 
  19. Finally, we can use the batch files in C:\Program Files\Atlassian\JIRA to recycle JIRA

    stop_service.bat
    start_service.bat
MySQL (5.7.19)
  1. Download an installer package from https://dev.mysql.com/downloads/
    1. Community Server
    2. Installer (instead of Zip file)
  2. Search on Google for "visual studio 2013 c++ redistributables", download and install
    1. The installer seems to have a provision to locate and install, but it didn't work for me
  3. We only need the server and command line tools, but I wasn't sure if MySQL Server (only) includes the command line tools, so I used Custom, then chose MySQL Server X64, then ticked only
    1. MySQL Server
      1. Client Programs
    2. Server data files
  4. Click Next, then Execute
  5. Choose (where not specified, use defaults, and provide your own root password)
    1. "Standalone MySQL Server"
    2. Config Type: Server Machine
  6. Complete installation
Mantis
  1. Paste the MySQL dump file into the MySQL bin folder, e.g. C:\Program Files\MySQL\MySQL Server 5.7\bin
  2. Run MySQL command line from C:\Program Files\MySQL\MySQL Server 5.7\bin>mysql -u root -p
  3. In MySQL, run the following commands to create a new db and restore from dump (change the file name):

    mysql> create database mantis;
    mysql> use mantis;
    mysql> source dumpfilename.sql;
  4. Note: I had to 
Import Mantis to JIRA
  1. As per https://confluence.atlassian.com/adminjiraserver074/connecting-jira-applications-to-mysql-881683181.html, download the MySQL connector from https://dev.mysql.com/downloads/connector/j/
  2. Get the mysql-connector-java-5.1.43-bin.jar (any version) from the zip file and paste into C:\Program Files\Atlassian\JIRA\lib
  3. Stop and start JIRA service
  4. Use the menu item, Create Project -> Import and follow the steps



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.