Creating a Buy One Get One Half Off Discount In NopCommerce

I recently worked with a client on trying to set up a Buy One Get One Half Off deal on NopCommerce – here’s what I did to get it working:

Requirements

Before starting, you should have the following:

Process

Go to the Discounts page and create a new Discount with the following information:

Next, go to the ‘Restrictions’ tab and add a restriction for the Product, using the ‘Add Product’ functionality Make sure you add the :2 to the end to force purchase of two:

Deploying web.config with an Angular Project

When deploying an Angular project out to Azure, you’ll need to include a web.config file to allow for things such as the following:

  • Getting routing to work.
  • Serving static content.

First, create a web.config file in src/. Here’s an example of what it might look like:

<?xml version="1.0"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="Angular Routing" stopProcessing="true">
                <match url=".*" />
                <conditions logicalGrouping="MatchAll">
                    <add input="{REQUEST_FILENAME}" matchType="IsFile"
                         negate="true" />
                    <add input="{REQUEST_FILENAME}" matchType="IsDirectory"
                         negate="true" />
                </conditions>
                <action type="Rewrite" url="/" />
                </rule>
            </rules>
        </rewrite>
        <staticContent>
            <mimeMap fileExtension="woff" mimeType="application/font-woff" />
            <mimeMap fileExtension="json" mimeType="application/json" />
        </staticContent>
    </system.webServer>
</configuration>

After this is done, make a change to angular.json to bundle the web.config file in the build:

...
"assets": [
    /src/favicon.ico",
    /src/assets",
    /src/web.config"
],
...

Now let’s verify by running ng build --prod:

Adding Bootstrap To An Angular CLI Project

Pre-Reqs

Before setting this up, you’ll need to have an Angular project to add Bootstrap to. If you’re starting fresh, you can create one easily with ng new <name>.

Procedure

First, install bootstrap from npm:

npm install bootstrap

Then add the following to the top of your styles.css file:

@import '~bootstrap/dist/css/bootstrap.min.css';

That’s it! Bootstrap is now enabled for your Angular CLI application.

Setting up WordPress in Azure with AKS and Helm

To get started, you’ll need the following:

  • kubectl
  • helm
  • Azure subscription

Installing WordPress in AKS with Helm

Set up an Azure Kubernetes Service with the following:

  • Node size – desired VM size (cheapest available is B2s)
  • Node count – need to use at least a minimum of 1.

After AKS is set up, connect to it with the following:

az aks get-credentials --resource-group AKS_RG --name AKS_NAME

Install Helm:

helm init

Create a values.yml file:

wordpressUsername: sammy
wordpressEmail: sammy@example.com
wordpressFirstName: Sammy
wordpressLastName: the Shark
wordpressBlogName: Sammy's Blog!

Create a second file values.secret.yml:

wordpressPassword: password

Now install WordPress with the following commands:

helm install --name blog -f values.yml -f values.secrets.yml stable/wordpress

After installation, run the following command to get the external IP:

kubectl get svc --namespace default -w blog-wordpress

Once the IP is ready, you’ll likely need to wait for the pods to finish loading. You can check their status with:

kubectl get pods

Once ready, try accessing the IP address to get the WordPress installation.

Reference: https://www.digitalocean.com/community/tutorials/how-to-set-up-wordpress-with-mysql-on-kubernetes-using-helm

Setting Up SonarQube in Azure with Azure AD Integration

Installing SonarQube

Go to the marketplace and install SonarQube from Bitnami – https://bitnami.com/stack/sonarqube/cloud/azure with the following:

  • resize to D1_v2
  • if desired, configure any NSG restrictions

After creation, set a DNS name label for the IP address.

Access using the domain name, and follow the directions in the link above to log in.

Setting up Azure AD Integration

Setting up HTTPS

To be able to use Azure AD, you have to use HTTPS.

Set up the Server base URL to be the configured HTTPS address in Administration → Configuration → General → Server base URL:

SSH into the server and set up a Let’s Encrypt script and enforce redirection to HTTPS here (make sure you aren’t behind a firewall to allow for Let’s Encrypt).

Restart Apache:

sudo /opt/bitnami/ctlscript.sh restart apache

Verify that trying to access the HTTP version of SonarQube automatically redirects you to the HTTPS version.

Creating App Registration in Azure

Run the following command in CLI to generate a service principal:

az ad sp create-for-rbac --name="{NAME}" --role="Contributor" --scope="/subscriptions/{SUBSCRIPTION_ID}" --years=100

You should receive some output data, which you will use when filling out info in SonarQube:

Set the Reply URL of the application to https://<URL>/oauth2/callback/aad:

Set the required permissions:

  • Sign in and read user profile
  • Read all users’ basic profiles

Installing Plug-in

Install the Azure Active Directory (AAD) Authentication Plug-in for SonarQube (restarting when requested):

Configure in Administration → General Settings → Azure Active Directory:

  1. Activate Azure AD
  2. Use the value in “appId”
  3. Use the value in “password”
  4. Use the value in “tenant”
  5. Allow users to sign-up.

Log out as admin, and verify the ability to log in as an Azure AD user.

Create Multiple Terraform Resources with a Map

I recently worked through a case in Terraform where I wanted to be able to pass in a map for Terraform to allow creating secrets in an Azure Key Vault. We’ll use the count, keys(, and values( helpers to iterate through the map.

This code sample will show a way to dynamically determine the amount of resources needed. In this case, this will create secrets based on the map provided in the Terraform variable:

variable "vault_secrets" {
  secret_name_1 = "secret_value_1"
  secret_name_2 = "secret_value_2"
  secret_name_3 = "secret_value_3"
}

resource "azurerm_key_vault" "vault" {
  name                = "example-vault"
  location            = "${var.rg_location}"
  resource_group_name = "${var.rg_name}"
  tenant_id           = "00000000-0000-0000-0000-000000000000"

  sku {
    name = "standard"
  }
}

resource "azurerm_key_vault_secret" "secret" {
  count = "${length(keys(var.vault_secrets))}"

  name         = "${element(keys(var.vault_secrets), count.index)}"
  value        = "${element(values(var.vault_secrets), count.index)}"
  key_vault_id = "${azurerm_key_vault.vault.id}"
}

Setting up WordPress in Azure with SSL for ~$8 a Month

  • Basic plan (allowing for Always on and SSL): ~$50/month
  • MySQL for Azure: ~$25
  • With this solution, you will create everything on one virtual machine, allowing for dynamic scaling as needed for the machine. This does of course come with some downside:

    • You will need to handle backing up of both the files on the server and the data in the database.

    Creating the VM

    First, create the VM and Resource Group:

    • RG name: <app>-<env>-<location>-rg
    • VM name: <app>-<env>-<location>-vm
    • Image: Ubuntu 18.04 LTS
    • VM size: B1s
    • VNet name: <app>-<env>-<location>-vnet
    • Diagnostics Storage Account: <app><env><location>vmdiag
    • Allow Inbound Port Access for HTTP, HTTPS, SSH
    • Login access through Azure Active Directory

    Once the VM is created, access the NSG and add a restriction to IP to only allow your local IP to access:

    Access VM and Install LAMP Server

    Retrieve the public IP address and SSH into the server:

    ssh <user>@<public_ip>

    Install LAMP Server:

    sudo apt update && sudo apt install lamp-server^

    To ensure the installation happened successfully, run the following commands:

    apache2 -v
    mysql -V
    php -v

    Once LAMP server is installed, verify that you can connect to HTTP using the public IP address – you should see the Apache2 Ubuntu Default Page:

     

    Set up MySQL

    Once the web server is running, the next step is configuring MySQL. Run the following command, installing the Validate Password Plugin and using “Medium” policy:

    sudo mysql_secure_installation

    When installing, use medium strength, and default yes to all options except “Disallow root login remotely?” Generate a password.
    The next step is configuring access to MySQL through external servers (such as from a VPN). This assumes you’ll be using the NSG from Azure to restrict access based on desired IP addresses.
    Run a query to allow access:

    sudo mysql -u root -p
    GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION; FLUSH PRIVILEGES;

    Edit MySQL configuration:

    sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf

    Comment out the line that says ‘bind-address’.
    After making that change, restart MySQL:

    sudo service mysql restart

    Finally, create an NSG rule that allows for external access to port 3306:

    Once the installation is done, let’s verify that the MySQL server can be accessed. I usually use MySQL Workbench and connect to the server using the following information:

    • Hostname: public IP

    After MySQL is set up, set up any database that may be needed.
    Here, you’ll want to set up the WordPress database server, whether you are starting fresh or migrating from an old instance.
    If running into an issue with packet size, run the following command in MySQL and restart:

    sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf

    The final step is creating a DB user specifically for the WordPress installation – this use would only have access to the specific database that WordPress uses. Create a user with the following:

    • Allow access to the DB used for the WordPress installation.

    Installing WordPress

    After finishing setting up the LAMP server, next is installing WordPress. Assuming you’ve downloaded the source, you can use the following:

    scp -r .\wordpress-download\ vmadmin@YOUR_SERVER_IP:~

    Now you’ll need to SSH into the server and move the files into /var/www/html:

    sudo mv -v ~/wordpress-download/* /var/www/html/

    Before doing the 5-minute install, run the following to allow for Apache to have write permissions:
    Check the group that Apache is running under:

    cat /etc/apache2/apache2.conf | grep ^Group -B 2
    cat /etc/apache2/envvars | grep GROUP
    # Give that group access
    sudo chown -R www-data:www-data /var/www/html
    sudo find /var/www/html -type d -exec chmod 755 {} \;
    sudo find /var/www/html -type f -exec chmod 644 {} \;
    

    Now perform the 5-minute install to ensure everything is working, you can access the site using the IP address to ensure everything in place.
    While doing this, make sure you can do the following:

    • Configure Apache to use .htaccess files. Change the following in apache2.conf to change AllowOverride to All:
      • <Directory /var/www/>
          Options Indexes FollowSymLinks
          AllowOverride None
          Require all granted
        </Directory>
    • Access a page outside of the home page (sudo a2enmod rewrite && sudo systemctl restart apache2)
    • Upload a media file to test uploads

    Enabling Mail (using G Suite)

    First, set up DNS to use email. For this example, we are using Google Suite for email. Add the following 5 MX records:

    • Host: @
    • Records (priority-URL)
      • 1-ASPMX.L.GOOGLE.COM.
      • 5-ALT1.ASPMX.L.GOOGLE.COM.
      • 5-ALT2.ASPMX.L.GOOGLE.COM.
      • 10-ALT3.ASPMX.L.GOOGLE.COM.
      • 10-ALT4.ASPMX.L.GOOGLE.COM.

    Then, do the following:
    https://wpforms.com/how-to-securely-send-wordpress-emails-using-gmail-smtp/

    Setting up SSL

    Once the web server can be reached and LAMP is installed, the next step is securing the site using SSL. Run the following to enable SSL, enable the SSL site, and restart Apache:

    sudo a2enmod ssl
    sudo a2ensite default-ssl
    sudo systemctl reload apache2

    Once that’s done, access the public IP using HTTPS – you should get an insecure cert warning.
    Now that we’ve determined the port is listening, let’s set up Let’s Encrypt. Using CertBot usually makes this much easier. Since in this case, we’re using Apache and Ubuntu 18.04, we just need to populate those values and run the commands provided by CertBot:

    With these commands, you’ll also need to set up DNS for the domain to use. With the public IP address, create the following:

    • create an A record with the host as @ and the IP address as the web server IP address.

    After this finishes, run the CertBot job to create the certificate. After that finishes, allow for the ability to redirect to HTTPS using the CertBot plugin.
    Reference:

    ]]>

    Create a Java Web App with Spring Boot Starter, Gradle, and Azure Active Directory

    Working on a project that would eventually use Azure Active Directory for authentication, I wanted to use Microsoft’s guide to get started with an app that could authenticate. However, the guide is written using Maven – and in our case, we are using Gradle for builds across the ecosystem.

    I was able to mostly follow the guide provided, but ran into a gotcha – involving having to add a fixed dependency to get the system working. In addition, I added a secondary API endpoint to allow for testing both with and without group authentication.

    To get started, you’ll need the following:

    Create an App With Spring Initializr

    To get started, create an app at https://start.spring.io/ with the following information:

    • Project: Gradle
    • Project Metadata Artifact: oauth2-demo-gradle
    • Dependencies: Web, Security, Azure Active Directory

    After clicking ‘Generate Project’, a ZIP file will be created. Extract this file to someone on your local machine, as you’ll be configuring it later.

    Set Up Azure Active Directory

    After the app is created, the next step is setting up Azure Active Directory for authentication. Follow the Create Azure Active Directory instance section, taking note of the App Registration information provided.

    Once you get to the section involving configuration of the app, come back to this guide – you’ll make specific changes to make the testing experience both compatible with Gradle and a little more user-friendly.

    Configure and Compile the App

    Once Azure Active Directory is configured, open your Java IDE and import the build.gradle file as a project. After that’s done, there are a few files to configure/create.

    Add the following dependencies into the build.gradle file (notice the third dependency, if this one is not added, you’ll run into an exception when testing):

    implementation 'org.springframework.security:spring-security-oauth2-client'
    implementation 'org.springframework.security:spring-security-oauth2-jose'
    implementation 'com.nimbusds:oauth2-oidc-sdk:5.64.4'

    Edit /src/main/resources/application.properties to look like the following:

    # Specifies your Active Directory ID:
    azure.activedirectory.tenant-id=22222222-2222-2222-2222-222222222222
    
    # Specifies your App Registration's Application ID:
    spring.security.oauth2.client.registration.azure.client-id=11111111-1111-1111-1111-1111111111111111
    
    # Specifies your App Registration's secret key:
    spring.security.oauth2.client.registration.azure.client-secret=AbCdEfGhIjKlMnOpQrStUvWxYz==
    
    # Specifies the list of Active Directory groups to use for authorization:
    azure.activedirectory.active-directory-groups=Users

    Create a file called /controller/HelloController.java and add the following:

    package com.example.oauth2demogradle.controller;
    
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.access.prepost.PreAuthorize;
    
    @RestController
    public class HelloController {
        @Autowired
        @RequestMapping("/version")
        public String helloWorld() {
            return "Hello World! (no auth required)";
        }
    
        @Autowired
        @RequestMapping("/secure")
        public String helloWorldSecure() {
            return "Hello World! (authenticated in Azure AD)";
        }
    
        @Autowired
        @PreAuthorize("hasRole('bams-devops')")
        @RequestMapping("/secureByGroup")
        public String helloWorldByGroup() {
            return "Hello World! (pre-authorized via AD group)";
        }
    }

    Create another file called security/WebSecurityConfig.java and add the following:

    package com.example.oauth2demogradle.security;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
    import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
    import org.springframework.security.oauth2.core.oidc.user.OidcUser;
    
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService;
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests()
                    .antMatchers("/version").permitAll()
                    .anyRequest().authenticated()
                    .and()
                    .oauth2Login()
                    .userInfoEndpoint()
                    .oidcUserService(oidcUserService);
        }
    }

    Build and Verify App

    Now that the configuration is complete, next step is building and testing. Run the following Gradle commands (easy way to do this is through the IDE):

    clean
    build
    bootRun

    You should end up with a log like the following:

    Once this is confirmed, access http://localhost:8080/version. You should be able to access without logging into Azure.

    Next, check http://localhost:8080/secure. You should receive a request to log in to Azure services. Log in as the user created in the step above, and you should be able to get a Hello World message.

    Finally, confirm that the /secureByGroup endpoint is also working. This endpoint will verify the logged in user is part of a verified group.

    This code can be found at

    Reference: https://docs.microsoft.com/en-us/java/azure/spring-framework/configure-spring-boot-starter-java-app-with-azure-active-directory?view=azure-java-stable

    ]]>